From 23c1c6557af76d506a28bcb3e864d3500e6dc565 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 24 Feb 2009 11:54:16 -0600 Subject: Major hacking to minimal config. 2009-02-24 David Smith * print.h: New file. * print.c: Includes new print.h file. * print_new.c (stp_print_flush): Commented out some code that needs replacing. * sym.c: Includes sym.h. * transport/debugfs.c: Includes transport.h. * transport/relayfs.c: Updated _stp_get_root_dir() call. * transport/transport.c: Ifdef'ed out most setup. * transport/transport.h: Ifdef'ed out all but basics. * transport/utt.c (utt_create_tree): Updated _stp_get_root_dir() call. * transport/utt.h: Commented out 'rchan' in struct utt_trace. (utt_reserve): Ifdef'ed out guts. --- runtime/print.c | 1 + runtime/print.h | 16 +++++ runtime/print_new.c | 5 +- runtime/sym.c | 1 + runtime/transport/debugfs.c | 1 + runtime/transport/relayfs.c | 2 +- runtime/transport/transport.c | 140 ++++++++++++++++++++++++++++++++++-------- runtime/transport/transport.h | 36 ++++++++--- runtime/transport/utt.c | 4 +- runtime/transport/utt.h | 9 ++- 10 files changed, 175 insertions(+), 40 deletions(-) create mode 100644 runtime/print.h diff --git a/runtime/print.c b/runtime/print.c index 2c84d3c9..fa517cb5 100644 --- a/runtime/print.c +++ b/runtime/print.c @@ -14,6 +14,7 @@ #include "string.h" #include "vsprintf.c" +#include "print.h" #include "transport/transport.c" /** @file print.c diff --git a/runtime/print.h b/runtime/print.h new file mode 100644 index 00000000..d5c588a3 --- /dev/null +++ b/runtime/print.h @@ -0,0 +1,16 @@ +/* -*- linux-c -*- + * Copyright (C) 2009 Red Hat Inc. + * + * This file is part of systemtap, and is free software. You can + * redistribute it and/or modify it under the terms of the GNU General + * Public License (GPL); either version 2, or (at your option) any + * later version. + */ + +#ifndef _STP_PRINT_H_ +#define _STP_PRINT_H_ + +static int _stp_print_init(void); +static void _stp_print_cleanup(void); + +#endif /* _STP_PRINT_H_ */ diff --git a/runtime/print_new.c b/runtime/print_new.c index fa7b4727..43e37822 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -28,8 +28,9 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) pb->len = 0; - if (unlikely(!_stp_utt || _stp_utt->trace_state != Utt_trace_running)) - return; +//DRS FIXME: this digs down too deep in internals +// if (unlikely(!_stp_utt || _stp_utt->trace_state != Utt_trace_running)) +// return; #ifdef STP_BULKMODE { diff --git a/runtime/sym.c b/runtime/sym.c index 1d88a862..31700326 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -12,6 +12,7 @@ #ifndef _STP_SYM_C_ #define _STP_SYM_C_ +#include "sym.h" #include "string.c" /** @file sym.c diff --git a/runtime/transport/debugfs.c b/runtime/transport/debugfs.c index 85ee604d..7de57335 100644 --- a/runtime/transport/debugfs.c +++ b/runtime/transport/debugfs.c @@ -10,6 +10,7 @@ */ #include +#include "transport.h" #define STP_DEFAULT_BUFFERS 50 diff --git a/runtime/transport/relayfs.c b/runtime/transport/relayfs.c index 6eefda8d..42be4283 100644 --- a/runtime/transport/relayfs.c +++ b/runtime/transport/relayfs.c @@ -86,7 +86,7 @@ static struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts) if (!utt) return NULL; - utt->utt_tree_root = _stp_get_root_dir(utts->root); + utt->utt_tree_root = _stp_get_root_dir(); if (!utt->utt_tree_root) goto err; diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 7fcebd42..2d82270a 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -14,10 +14,21 @@ #ifndef _TRANSPORT_TRANSPORT_C_ #define _TRANSPORT_TRANSPORT_C_ -#include -#include #include "transport.h" -#include "time.c" +struct utt_trace { + int dummy; +}; +static struct utt_trace *_stp_utt = NULL; +static int _stp_ctl_write(int type, void *data, unsigned len) { + return 0; +} + +static int _stp_exit_flag = 0; + +#include +#include +#if 0 +#include #include "../mempool.c" #include "symbols.c" @@ -37,10 +48,15 @@ static int _stp_exit_flag = 0; #endif #include "control.c" +#endif /* if 0 */ +static unsigned _stp_nsubbufs = 8; +static unsigned _stp_subbuf_size = 65536*4; + /* module parameters */ static int _stp_bufsize; module_param(_stp_bufsize, int, 0); MODULE_PARM_DESC(_stp_bufsize, "buffer size"); +#if 0 /* forward declarations */ static void probe_exit(void); @@ -173,6 +189,7 @@ static void _stp_work_queue(void *data) if (likely(_stp_attached)) queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); } +#endif /* #if 0 */ /** * _stp_transport_close - close ctl and relayfs channels @@ -180,9 +197,11 @@ static void _stp_work_queue(void *data) * This is called automatically when the module is unloaded. * */ -static void _stp_transport_close() +static void _stp_transport_close(void) { - dbug_trans(1, "%d: ************** transport_close *************\n", current->pid); + dbug_trans(1, "%d: ************** transport_close *************\n", + current->pid); +#if 0 _stp_cleanup_and_exit(0); destroy_workqueue(_stp_wq); _stp_unregister_ctl_channel(); @@ -190,9 +209,13 @@ static void _stp_transport_close() utt_trace_remove(_stp_utt); _stp_print_cleanup(); /* free print buffers */ _stp_mem_debug_done(); +#endif + _stp_transport_fs_close(); + dbug_trans(1, "---- CLOSED ----\n"); } +#if 0 static struct utt_trace *_stp_utt_open(void) { struct utt_trace_setup utts; @@ -209,6 +232,7 @@ static struct utt_trace *_stp_utt_open(void) return utt_trace_setup(&utts); } +#endif /* #if 0 */ /** * _stp_transport_init() is called from the module initialization. @@ -217,7 +241,6 @@ static struct utt_trace *_stp_utt_open(void) static int _stp_transport_init(void) { dbug_trans(1, "transport_init\n"); - _stp_init_pid = current->pid; #ifdef STAPCONF_TASK_UID _stp_uid = current->uid; _stp_gid = current->gid; @@ -226,6 +249,8 @@ static int _stp_transport_init(void) _stp_gid = current_gid(); #endif +// DRS: is RELAY_GUEST/RELAY_HOST documented? does it work? are there +// test cases? #ifdef RELAY_GUEST /* Guest scripts use relay only for reporting warnings and errors */ _stp_subbuf_size = 65536; @@ -243,6 +268,10 @@ static int _stp_transport_init(void) dbug_trans(1, "Using %d subbufs of size %d\n", _stp_nsubbufs, _stp_subbuf_size); } + if (_stp_transport_fs_init(THIS_MODULE->name)) + return -1; + +#if 0 #if !defined (STP_OLD_TRANSPORT) || defined (STP_BULKMODE) /* open utt (relayfs) channel to send data to userspace */ _stp_utt = _stp_utt_open(); @@ -253,11 +282,13 @@ static int _stp_transport_init(void) /* create control channel */ if (_stp_register_ctl_channel() < 0) goto err1; +#endif /* #if 0 */ /* create print buffers */ if (_stp_print_init() < 0) goto err2; +#if 0 /* start transport */ utt_trace_startstop(_stp_utt, 1, &utt_seq); @@ -270,16 +301,19 @@ static int _stp_transport_init(void) /* Signal stapio to send us STP_START back (XXX: ?!?!?!). */ _stp_ctl_send(STP_TRANSPORT, NULL, 0); +#endif /* #if 0 */ return 0; err3: _stp_print_cleanup(); err2: +#if 0 _stp_unregister_ctl_channel(); err1: if (_stp_utt) utt_trace_remove(_stp_utt); +#endif /* #if 0 */ err0: return -1; } @@ -331,51 +365,109 @@ static void _stp_unlock_transport_dir(void) } } -/* _stp_get_root_dir(name) - creates root directory 'name' or */ -/* returns a pointer to it if it already exists. Used in */ -/* utt.c and relayfs.c. Will not be necessary if utt is included */ -/* in the kernel. */ +static struct dentry *__stp_root_dir = NULL; -static struct dentry *_stp_get_root_dir(const char *name) +/* _stp_get_root_dir() - creates root directory or returns + * a pointer to it if it already exists. */ + +static struct dentry *_stp_get_root_dir(void) { struct file_system_type *fs; - struct dentry *root; struct super_block *sb; + const char *name = "systemtap"; + + if (__stp_root_dir != NULL) { + return __stp_root_dir; + } #ifdef STP_OLD_TRANSPORT fs = get_fs_type("relayfs"); + if (!fs) { + errk("Couldn't find relayfs filesystem.\n"); + return NULL; + } #else fs = get_fs_type("debugfs"); -#endif if (!fs) { - errk("Couldn't find debugfs or relayfs filesystem.\n"); + errk("Couldn't find debugfs filesystem.\n"); return NULL; } +#endif if (!_stp_lock_transport_dir()) { errk("Couldn't lock transport directory.\n"); return NULL; } #ifdef STP_OLD_TRANSPORT - root = relayfs_create_dir(name, NULL); + __stp_root_dir = relayfs_create_dir(name, NULL); #else - root = debugfs_create_dir(name, NULL); + __stp_root_dir = debugfs_create_dir(name, NULL); #endif - if (!root) { - /* couldn't create it because it is already there, so find it. */ - sb = list_entry(fs->fs_supers.next, struct super_block, s_instances); + if (!__stp_root_dir) { + /* Couldn't create it because it is already there, so + * find it. */ + sb = list_entry(fs->fs_supers.next, struct super_block, + s_instances); _stp_lock_inode(sb->s_root->d_inode); - root = lookup_one_len(name, sb->s_root, strlen(name)); + __stp_root_dir = lookup_one_len(name, sb->s_root, + strlen(name)); _stp_unlock_inode(sb->s_root->d_inode); - if (!IS_ERR(root)) - dput(root); + if (!IS_ERR(__stp_root_dir)) + dput(__stp_root_dir); else { - root = NULL; + __stp_root_dir = NULL; errk("Could not create or find transport directory.\n"); } } _stp_unlock_transport_dir(); - return root; + return __stp_root_dir; +} + +static void _stp_remove_root_dir(void) +{ + if (__stp_root_dir) { + if (!_stp_lock_transport_dir()) { + errk("Unable to lock transport directory.\n"); + return; + } + if (simple_empty(__stp_root_dir)) + debugfs_remove(__stp_root_dir); + _stp_unlock_transport_dir(); + __stp_root_dir = NULL; + } } +static struct dentry *__stp_module_dir = NULL; + +static int _stp_transport_fs_init(const char *module_name) +{ + struct dentry *root_dir; + + if (module_name == NULL) + return -1; + + root_dir = _stp_get_root_dir(); + if (root_dir == NULL) + return -1; + + __stp_module_dir = debugfs_create_dir(module_name, root_dir); + if (!__stp_module_dir) { + _stp_remove_root_dir(); + return -1; + } + return 0; +} + +static void _stp_transport_fs_close(void) +{ + dbug_trans(1, "stp_transport_fs_close\n"); + if (__stp_module_dir) { + debugfs_remove(__stp_module_dir); + __stp_module_dir = NULL; + } + + _stp_remove_root_dir(); +} + + #endif /* _TRANSPORT_C_ */ diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index 7d249c45..c6d850ef 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -11,6 +11,20 @@ /* amount of data a print can send. */ #define STP_BUFFER_SIZE 8192 +struct utt_trace; + +static int _stp_ctl_write(int type, void *data, unsigned len); + +static int _stp_transport_init(void); +static void _stp_transport_close(void); + +static inline void *utt_reserve(struct utt_trace *utt, size_t length) +{ + return NULL; +} + + +#if 0 /* STP_CTL_BUFFER_SIZE is the maximum size of a message */ /* exchanged on the control channel. */ #ifdef STP_OLD_TRANSPORT @@ -23,27 +37,33 @@ /* how often the work queue wakes up and checks buffers */ #define STP_WORK_TIMER (HZ/100) -static unsigned _stp_nsubbufs = 8; -static unsigned _stp_subbuf_size = 65536*4; +#endif /* #if 0 */ +static unsigned _stp_nsubbufs; +static unsigned _stp_subbuf_size; static int _stp_transport_init(void); static void _stp_transport_close(void); -static void _stp_warn (const char *fmt, ...); -static int _stp_print_init(void); -static void _stp_print_cleanup(void); -static struct dentry *_stp_get_root_dir(const char *name); - static int _stp_lock_transport_dir(void); static void _stp_unlock_transport_dir(void); +static struct dentry *_stp_get_root_dir(void); + +static int _stp_transport_fs_init(const char *module_name); +static void _stp_transport_fs_close(void); + +#if 0 +static void _stp_warn (const char *fmt, ...); + static void _stp_attach(void); static void _stp_detach(void); static void _stp_handle_start(struct _stp_msg_start *st); static int _stp_pid = 0; +#endif static uid_t _stp_uid = 0; static gid_t _stp_gid = 0; -static pid_t _stp_init_pid = 0; +#if 0 static int _stp_attached = 0; +#endif #endif /* _TRANSPORT_TRANSPORT_H_ */ diff --git a/runtime/transport/utt.c b/runtime/transport/utt.c index 915662b2..2dd303a5 100644 --- a/runtime/transport/utt.c +++ b/runtime/transport/utt.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include "utt.h" @@ -157,7 +156,7 @@ static struct dentry *utt_create_tree(struct utt_trace *utt, const char *root, c return NULL; if (!utt->utt_tree_root) { - utt->utt_tree_root = _stp_get_root_dir(root); + utt->utt_tree_root = _stp_get_root_dir(); if (!utt->utt_tree_root) goto err; } @@ -169,7 +168,6 @@ err: return dir; } - static void utt_trace_cleanup(struct utt_trace *utt) { if (utt == NULL) diff --git a/runtime/transport/utt.h b/runtime/transport/utt.h index 40e54919..0a0944c0 100644 --- a/runtime/transport/utt.h +++ b/runtime/transport/utt.h @@ -9,11 +9,11 @@ enum { struct utt_trace { int trace_state; - struct rchan *rchan; +// struct rchan *rchan; struct dentry *dir; /* systemtap/module_name */ struct dentry *dropped_file; atomic_t dropped; - struct dentry *utt_tree_root; /* systemtap */ + struct dentry *utt_tree_root; /* systemtap */ void *private_data; atomic_t wakeup; struct timer_list timer; @@ -41,6 +41,7 @@ struct utt_trace_setup { static struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts); + static int utt_trace_startstop(struct utt_trace *utt, int start, unsigned int *trace_seq); static void utt_trace_cleanup(struct utt_trace *utt); @@ -60,6 +61,7 @@ static size_t utt_switch_subbuf(struct utt_trace *utt, struct rchan_buf *buf, */ static inline void *utt_reserve(struct utt_trace *utt, size_t length) { +#if 0 void *reserved; struct rchan_buf *buf = utt->rchan->buf[smp_processor_id()]; @@ -72,6 +74,9 @@ static inline void *utt_reserve(struct utt_trace *utt, size_t length) buf->offset += length; return reserved; +#else + return NULL; +#endif } #endif -- cgit From 64c962fed5f50a7f82f8b570e000cdcff757862b Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 25 Feb 2009 09:04:19 -0600 Subject: More cleanup. 2009-02-25 David Smith * debug.h: Removed unused variable '_stp_transport_state'. * print_new.c (stp_print_flush): Ifdef'ed out call to utt_reserve(). * runtime.h: Added _stp_warn() prototype. * transport/control.c: Includes control.h, mempool.c, and symbols.c. Renamed '_stp_attached' to '_stp_ctl_attached'. * transport/control.h: Removed _stp_pool_q declaration. * transport/debugfs.c (_stp_register_ctl_channel_fs): Uses _stp_get_module_dir(). * transport/transport.c: Cleanup. * transport/transport.h: Ditto. --- runtime/debug.h | 1 - runtime/print_new.c | 4 +++ runtime/runtime.h | 1 + runtime/transport/control.c | 8 +++-- runtime/transport/control.h | 1 - runtime/transport/debugfs.c | 7 +++-- runtime/transport/transport.c | 68 ++++++++++++++++++++++++++++++------------- runtime/transport/transport.h | 18 ++++-------- 8 files changed, 68 insertions(+), 40 deletions(-) diff --git a/runtime/debug.h b/runtime/debug.h index e8b2e701..ce0c3943 100644 --- a/runtime/debug.h +++ b/runtime/debug.h @@ -14,7 +14,6 @@ * _dbug() writes to systemtap stderr. * errk() writes to the system log. */ -static int _stp_transport_state = 0; #define _dbug(args...) _stp_dbug(__FUNCTION__, __LINE__, args) diff --git a/runtime/print_new.c b/runtime/print_new.c index 43e37822..bebaa19c 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -57,7 +57,11 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) void *buf; unsigned long flags; spin_lock_irqsave(&_stp_print_lock, flags); +#if 0 buf = utt_reserve(_stp_utt, len); +#else + buf = NULL; +#endif if (likely(buf)) memcpy(buf, pb->buf, len); else diff --git a/runtime/runtime.h b/runtime/runtime.h index fc5d454f..25456beb 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -45,6 +45,7 @@ static void _stp_dbug (const char *func, int line, const char *fmt, ...); static void _stp_error (const char *fmt, ...); +static void _stp_warn (const char *fmt, ...); #include "debug.h" diff --git a/runtime/transport/control.c b/runtime/transport/control.c index edde244d..7626305a 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -9,6 +9,10 @@ * later version. */ +#include "control.h" +#include "../mempool.c" +#include "symbols.c" + static _stp_mempool_t *_stp_pool_q; static struct list_head _stp_ctl_ready_q; static DEFINE_SPINLOCK(_stp_ctl_ready_lock); @@ -192,7 +196,7 @@ static ssize_t _stp_ctl_read_cmd(struct file *file, char __user *buf, static int _stp_ctl_open_cmd(struct inode *inode, struct file *file) { - if (_stp_attached) + if (_stp_ctl_attached) return -1; _stp_attach(); return 0; @@ -200,7 +204,7 @@ static int _stp_ctl_open_cmd(struct inode *inode, struct file *file) static int _stp_ctl_close_cmd(struct inode *inode, struct file *file) { - if (_stp_attached) + if (_stp_ctl_attached) _stp_detach(); return 0; } diff --git a/runtime/transport/control.h b/runtime/transport/control.h index 5e7204ee..48289276 100644 --- a/runtime/transport/control.h +++ b/runtime/transport/control.h @@ -15,7 +15,6 @@ #include #include -static _stp_mempool_t *_stp_pool_q; static struct list_head _stp_ctl_ready_q; static spinlock_t _stp_ctl_ready_lock; static wait_queue_head_t _stp_ctl_wq; diff --git a/runtime/transport/debugfs.c b/runtime/transport/debugfs.c index 7de57335..7a08982a 100644 --- a/runtime/transport/debugfs.c +++ b/runtime/transport/debugfs.c @@ -23,13 +23,14 @@ static struct dentry *_stp_cmd_file = NULL; static int _stp_register_ctl_channel_fs(void) { - if (_stp_utt == NULL) { - errk("_expected _stp_utt to be set.\n"); + struct dentry *module_dir = _stp_get_module_dir(); + if (module_dir == NULL) { + errk("no module directory found.\n"); return -1; } /* create [debugfs]/systemtap/module_name/.cmd */ - _stp_cmd_file = debugfs_create_file(".cmd", 0600, _stp_utt->dir, + _stp_cmd_file = debugfs_create_file(".cmd", 0600, module_dir, NULL, &_stp_ctl_fops_cmd); if (_stp_cmd_file == NULL) { errk("Error creating systemtap debugfs entries.\n"); diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 2d82270a..12e98a38 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -15,29 +15,36 @@ #define _TRANSPORT_TRANSPORT_C_ #include "transport.h" +#include +#include +#include + struct utt_trace { int dummy; }; -static struct utt_trace *_stp_utt = NULL; -static int _stp_ctl_write(int type, void *data, unsigned len) { - return 0; +//static struct utt_trace *_stp_utt = NULL; + +static void utt_set_overwrite(int overwrite) +{ + return; } static int _stp_exit_flag = 0; -#include -#include +static uid_t _stp_uid = 0; +static gid_t _stp_gid = 0; +static int _stp_pid = 0; + +static int _stp_ctl_attached = 0; + +static pid_t _stp_target = 0; +static int _stp_probes_started = 0; + #if 0 #include -#include "../mempool.c" -#include "symbols.c" static struct utt_trace *_stp_utt = NULL; static unsigned int utt_seq = 1; -static int _stp_probes_started = 0; -static pid_t _stp_target = 0; -static int _stp_exit_called = 0; -static int _stp_exit_flag = 0; #include "control.h" #ifdef STP_OLD_TRANSPORT #include "relayfs.c" @@ -48,6 +55,10 @@ static int _stp_exit_flag = 0; #endif #include "control.c" +#else /* #if 0 */ +#include "control.h" +#include "debugfs.c" +#include "control.c" #endif /* if 0 */ static unsigned _stp_nsubbufs = 8; static unsigned _stp_subbuf_size = 65536*4; @@ -56,12 +67,13 @@ static unsigned _stp_subbuf_size = 65536*4; static int _stp_bufsize; module_param(_stp_bufsize, int, 0); MODULE_PARM_DESC(_stp_bufsize, "buffer size"); -#if 0 /* forward declarations */ static void probe_exit(void); static int probe_start(void); +#if 0 static void _stp_exit(void); +#endif /* #if 0 */ /* check for new workqueue API */ #ifdef DECLARE_DELAYED_WORK @@ -105,6 +117,8 @@ static void _stp_handle_start(struct _stp_msg_start *st) /* when someone does /sbin/rmmod on a loaded systemtap module. */ static void _stp_cleanup_and_exit(int send_exit) { + static int _stp_exit_called = 0; + if (!_stp_exit_called) { int failures; @@ -125,8 +139,10 @@ static void _stp_cleanup_and_exit(int send_exit) _stp_warn("There were %d transport failures.\n", failures); dbug_trans(1, "************** calling startstop 0 *************\n"); +#if 0 if (_stp_utt) utt_trace_startstop(_stp_utt, 0, &utt_seq); +#endif dbug_trans(1, "ctl_send STP_EXIT\n"); if (send_exit) @@ -141,7 +157,7 @@ static void _stp_cleanup_and_exit(int send_exit) static void _stp_detach(void) { dbug_trans(1, "detach\n"); - _stp_attached = 0; + _stp_ctl_attached = 0; _stp_pid = 0; if (!_stp_exit_flag) @@ -157,7 +173,7 @@ static void _stp_detach(void) static void _stp_attach(void) { dbug_trans(1, "attach\n"); - _stp_attached = 1; + _stp_ctl_attached = 1; _stp_pid = current->pid; utt_set_overwrite(0); queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); @@ -186,10 +202,9 @@ static void _stp_work_queue(void *data) /* if exit flag is set AND we have finished with probe_start() */ if (unlikely(_stp_exit_flag && _stp_probes_started)) _stp_cleanup_and_exit(1); - if (likely(_stp_attached)) + if (likely(_stp_ctl_attached)) queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); } -#endif /* #if 0 */ /** * _stp_transport_close - close ctl and relayfs channels @@ -203,13 +218,17 @@ static void _stp_transport_close(void) current->pid); #if 0 _stp_cleanup_and_exit(0); +#endif /* #if 0 */ destroy_workqueue(_stp_wq); _stp_unregister_ctl_channel(); +#if 0 if (_stp_utt) utt_trace_remove(_stp_utt); +#endif /* #if 0 */ _stp_print_cleanup(); /* free print buffers */ +#if 0 _stp_mem_debug_done(); -#endif +#endif /* #if 0 */ _stp_transport_fs_close(); dbug_trans(1, "---- CLOSED ----\n"); @@ -278,11 +297,11 @@ static int _stp_transport_init(void) if (!_stp_utt) goto err0; #endif +#endif /* #if 0 */ /* create control channel */ if (_stp_register_ctl_channel() < 0) goto err1; -#endif /* #if 0 */ /* create print buffers */ if (_stp_print_init() < 0) @@ -291,14 +310,14 @@ static int _stp_transport_init(void) #if 0 /* start transport */ utt_trace_startstop(_stp_utt, 1, &utt_seq); +#endif /* #if 0 */ /* create workqueue of kernel threads */ _stp_wq = create_workqueue("systemtap"); if (!_stp_wq) goto err3; - _stp_transport_state = 1; - +#if 0 /* Signal stapio to send us STP_START back (XXX: ?!?!?!). */ _stp_ctl_send(STP_TRANSPORT, NULL, 0); #endif /* #if 0 */ @@ -308,11 +327,13 @@ static int _stp_transport_init(void) err3: _stp_print_cleanup(); err2: -#if 0 _stp_unregister_ctl_channel(); err1: +#if 0 if (_stp_utt) utt_trace_remove(_stp_utt); +#else + _stp_transport_fs_close(); #endif /* #if 0 */ err0: return -1; @@ -439,6 +460,11 @@ static void _stp_remove_root_dir(void) static struct dentry *__stp_module_dir = NULL; +static inline struct dentry *_stp_get_module_dir(void) +{ + return __stp_module_dir; +} + static int _stp_transport_fs_init(const char *module_name) { struct dentry *root_dir; diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index c6d850ef..dec23c72 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -24,7 +24,6 @@ static inline void *utt_reserve(struct utt_trace *utt, size_t length) } -#if 0 /* STP_CTL_BUFFER_SIZE is the maximum size of a message */ /* exchanged on the control channel. */ #ifdef STP_OLD_TRANSPORT @@ -37,7 +36,6 @@ static inline void *utt_reserve(struct utt_trace *utt, size_t length) /* how often the work queue wakes up and checks buffers */ #define STP_WORK_TIMER (HZ/100) -#endif /* #if 0 */ static unsigned _stp_nsubbufs; static unsigned _stp_subbuf_size; @@ -48,22 +46,18 @@ static int _stp_lock_transport_dir(void); static void _stp_unlock_transport_dir(void); static struct dentry *_stp_get_root_dir(void); +static struct dentry *_stp_get_module_dir(void); static int _stp_transport_fs_init(const char *module_name); static void _stp_transport_fs_close(void); -#if 0 -static void _stp_warn (const char *fmt, ...); - static void _stp_attach(void); static void _stp_detach(void); static void _stp_handle_start(struct _stp_msg_start *st); -static int _stp_pid = 0; -#endif -static uid_t _stp_uid = 0; -static gid_t _stp_gid = 0; -#if 0 -static int _stp_attached = 0; -#endif +static uid_t _stp_uid; +static gid_t _stp_gid; + +static int _stp_ctl_attached; + #endif /* _TRANSPORT_TRANSPORT_H_ */ -- cgit 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/runtime.h | 2 + runtime/transport/ring_buffer.c | 338 ++++++++++++++++++++++++++++++++++++++++ runtime/transport/transport.c | 29 ++-- runtime/transport/transport.h | 4 + 4 files changed, 363 insertions(+), 10 deletions(-) create mode 100644 runtime/transport/ring_buffer.c diff --git a/runtime/runtime.h b/runtime/runtime.h index 25456beb..28283db6 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -47,6 +47,8 @@ static void _stp_dbug (const char *func, int line, const char *fmt, ...); static void _stp_error (const char *fmt, ...); static void _stp_warn (const char *fmt, ...); +static void _stp_exit(void); + #include "debug.h" /* atomic globals */ 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(); +} + diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 12e98a38..093d8b7b 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -19,11 +19,6 @@ #include #include -struct utt_trace { - int dummy; -}; -//static struct utt_trace *_stp_utt = NULL; - static void utt_set_overwrite(int overwrite) { return; @@ -59,6 +54,7 @@ static unsigned int utt_seq = 1; #include "control.h" #include "debugfs.c" #include "control.c" +#include "ring_buffer.c" #endif /* if 0 */ static unsigned _stp_nsubbufs = 8; static unsigned _stp_subbuf_size = 65536*4; @@ -71,9 +67,6 @@ MODULE_PARM_DESC(_stp_bufsize, "buffer size"); /* forward declarations */ static void probe_exit(void); static int probe_start(void); -#if 0 -static void _stp_exit(void); -#endif /* #if 0 */ /* check for new workqueue API */ #ifdef DECLARE_DELAYED_WORK @@ -287,8 +280,8 @@ static int _stp_transport_init(void) dbug_trans(1, "Using %d subbufs of size %d\n", _stp_nsubbufs, _stp_subbuf_size); } - if (_stp_transport_fs_init(THIS_MODULE->name)) - return -1; + if (_stp_transport_fs_init(THIS_MODULE->name) != 0) + goto err0; #if 0 #if !defined (STP_OLD_TRANSPORT) || defined (STP_BULKMODE) @@ -297,6 +290,7 @@ static int _stp_transport_init(void) if (!_stp_utt) goto err0; #endif +#else /* #if 0 */ #endif /* #if 0 */ /* create control channel */ @@ -322,20 +316,25 @@ static int _stp_transport_init(void) _stp_ctl_send(STP_TRANSPORT, NULL, 0); #endif /* #if 0 */ + dbug_trans(1, "returning 0...\n"); return 0; err3: + dbug_trans(1, "err3\n"); _stp_print_cleanup(); err2: + dbug_trans(1, "err2\n"); _stp_unregister_ctl_channel(); err1: #if 0 if (_stp_utt) utt_trace_remove(_stp_utt); #else + dbug_trans(1, "err1\n"); _stp_transport_fs_close(); #endif /* #if 0 */ err0: + dbug_trans(1, "err0\n"); return -1; } @@ -469,6 +468,7 @@ static int _stp_transport_fs_init(const char *module_name) { struct dentry *root_dir; + dbug_trans(1, "entry\n"); if (module_name == NULL) return -1; @@ -481,12 +481,21 @@ static int _stp_transport_fs_init(const char *module_name) _stp_remove_root_dir(); return -1; } + + if (_stp_transport_data_fs_init() != 0) { + _stp_remove_root_dir(); + return -1; + } + dbug_trans(1, "returning 0\n"); return 0; } static void _stp_transport_fs_close(void) { dbug_trans(1, "stp_transport_fs_close\n"); + + _stp_transport_data_fs_close(); + if (__stp_module_dir) { debugfs_remove(__stp_module_dir); __stp_module_dir = NULL; diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index dec23c72..c79549d4 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -60,4 +60,8 @@ static gid_t _stp_gid; static int _stp_ctl_attached; +static int _stp_bufsize; +static int _stp_transport_data_fs_init(void); +static void _stp_transport_data_fs_close(void); + #endif /* _TRANSPORT_TRANSPORT_H_ */ -- 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/print_new.c | 17 +-- runtime/transport/ring_buffer.c | 302 ++++++++++++++++++++++++++++++++-------- runtime/transport/transport.c | 6 - runtime/transport/transport.h | 9 ++ 4 files changed, 262 insertions(+), 72 deletions(-) diff --git a/runtime/print_new.c b/runtime/print_new.c index bebaa19c..2759ebcf 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -23,6 +23,7 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) uint32_t len = pb->len; /* check to see if there is anything in the buffer */ + dbug_trans(1, "len = %ud\n", len); if (likely (len == 0)) return; @@ -54,16 +55,16 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) } #else { - void *buf; + struct _stp_entry *entry; unsigned long flags; + + dbug_trans(1, "calling _stp_data_write...\n"); spin_lock_irqsave(&_stp_print_lock, flags); -#if 0 - buf = utt_reserve(_stp_utt, len); -#else - buf = NULL; -#endif - if (likely(buf)) - memcpy(buf, pb->buf, len); + entry = _stp_data_write_reserve(len); + if (likely(entry)) { + memcpy(entry->buf, pb->buf, len); + _stp_data_write_commit(entry); + } else atomic_inc (&_stp_transport_failures); spin_unlock_irqrestore(&_stp_print_lock, flags); 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"); diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 093d8b7b..c4c9da1e 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -209,9 +209,7 @@ static void _stp_transport_close(void) { dbug_trans(1, "%d: ************** transport_close *************\n", current->pid); -#if 0 _stp_cleanup_and_exit(0); -#endif /* #if 0 */ destroy_workqueue(_stp_wq); _stp_unregister_ctl_channel(); #if 0 @@ -219,9 +217,7 @@ static void _stp_transport_close(void) utt_trace_remove(_stp_utt); #endif /* #if 0 */ _stp_print_cleanup(); /* free print buffers */ -#if 0 _stp_mem_debug_done(); -#endif /* #if 0 */ _stp_transport_fs_close(); dbug_trans(1, "---- CLOSED ----\n"); @@ -311,10 +307,8 @@ static int _stp_transport_init(void) if (!_stp_wq) goto err3; -#if 0 /* Signal stapio to send us STP_START back (XXX: ?!?!?!). */ _stp_ctl_send(STP_TRANSPORT, NULL, 0); -#endif /* #if 0 */ dbug_trans(1, "returning 0...\n"); return 0; diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index c79549d4..feaa950c 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -64,4 +64,13 @@ static int _stp_bufsize; static int _stp_transport_data_fs_init(void); static void _stp_transport_data_fs_close(void); +struct _stp_entry { + void *event; + size_t len; + char buf[]; +}; + +static struct _stp_entry *_stp_data_write_reserve(size_t size); +static int _stp_data_write_commit(struct _stp_entry *entry); + #endif /* _TRANSPORT_TRANSPORT_H_ */ -- 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(-) 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/print_new.c | 30 +++++++++++++++++++++++++++++- runtime/transport/ring_buffer.c | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/runtime/print_new.c b/runtime/print_new.c index 2759ebcf..4e579c37 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -60,13 +60,41 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) dbug_trans(1, "calling _stp_data_write...\n"); spin_lock_irqsave(&_stp_print_lock, flags); +#if 0 entry = _stp_data_write_reserve(len); if (likely(entry)) { memcpy(entry->buf, pb->buf, len); _stp_data_write_commit(entry); } else - atomic_inc (&_stp_transport_failures); +#endif + { + uint32_t cnt; + char *bufp = pb->buf; + +#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 8) + while (len > 0) { + if (len > MAX_RESERVE_SIZE) { + len -= MAX_RESERVE_SIZE; + cnt = MAX_RESERVE_SIZE; + } + else { + cnt = len; + len = 0; + } + + entry = _stp_data_write_reserve(cnt); + if (likely(entry)) { + memcpy(entry->buf, bufp, cnt); + _stp_data_write_commit(entry); + bufp += cnt; + } + else { + atomic_inc (&_stp_transport_failures); + break; + } + } + } spin_unlock_irqrestore(&_stp_print_lock, flags); } #endif /* STP_BULKMODE */ 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 457debd23eb3eef17d24ecf3534891ec640684f6 Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 11 Mar 2009 16:07:39 -0500 Subject: Make printf tests fail when stap fails. 2009-03-11 David Smith * systemtap.printf/end1.exp: The test fails when stap fails. * systemtap.printf/end1b.exp: Ditto. * systemtap.printf/mixed_out.exp: Ditto. * systemtap.printf/mixed_outb.exp: Ditto. * systemtap.printf/out1.exp: Ditto. * systemtap.printf/out1b.exp: Ditto. * systemtap.printf/out2.exp: Ditto. * systemtap.printf/out2b.exp: Ditto. * systemtap.printf/out3.exp: Ditto. * systemtap.printf/out3b.exp: Ditto. --- testsuite/systemtap.printf/end1.exp | 6 +++--- testsuite/systemtap.printf/end1b.exp | 2 +- testsuite/systemtap.printf/mixed_out.exp | 4 ++-- testsuite/systemtap.printf/mixed_outb.exp | 2 +- testsuite/systemtap.printf/out1.exp | 2 +- testsuite/systemtap.printf/out1b.exp | 2 +- testsuite/systemtap.printf/out2.exp | 2 +- testsuite/systemtap.printf/out2b.exp | 2 +- testsuite/systemtap.printf/out3.exp | 2 +- testsuite/systemtap.printf/out3b.exp | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/testsuite/systemtap.printf/end1.exp b/testsuite/systemtap.printf/end1.exp index 0a4dd32e..e4f164f5 100644 --- a/testsuite/systemtap.printf/end1.exp +++ b/testsuite/systemtap.printf/end1.exp @@ -11,15 +11,15 @@ if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} { } if {[catch {exec stap -o $tmpfile $tpath} res]} { - untested $TEST_NAME - puts "$res" + fail $TEST_NAME + puts "stap failed: $res" catch {exec rm -f $tmpfile} return } if {[catch {exec cmp $tmpfile $srcdir/$subdir/large_output} res]} { - fail $TEST_NAME puts "$res" + fail $TEST_NAME catch {exec rm -f $tmpfile} return } diff --git a/testsuite/systemtap.printf/end1b.exp b/testsuite/systemtap.printf/end1b.exp index 1764a383..08cfa648 100644 --- a/testsuite/systemtap.printf/end1b.exp +++ b/testsuite/systemtap.printf/end1b.exp @@ -16,8 +16,8 @@ if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} { } if {[catch {exec stap -b -o $tmpfile $test} res]} { - untested $TEST_NAME puts "stap failed: $res" + fail $TEST_NAME as_root "/bin/rm -f [glob ${tmpfile}*]" return } diff --git a/testsuite/systemtap.printf/mixed_out.exp b/testsuite/systemtap.printf/mixed_out.exp index 093a8ca1..d73a55a6 100644 --- a/testsuite/systemtap.printf/mixed_out.exp +++ b/testsuite/systemtap.printf/mixed_out.exp @@ -11,8 +11,8 @@ if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} { } if {[catch {exec stap -DMAXACTION=100000 -o $tmpfile $tpath} res]} { - untested $TEST_NAME - puts "$res" + fail $TEST_NAME + puts "stap failed: $res" catch {exec rm -f $tmpfile} return } diff --git a/testsuite/systemtap.printf/mixed_outb.exp b/testsuite/systemtap.printf/mixed_outb.exp index cbf7b920..30c0c92f 100644 --- a/testsuite/systemtap.printf/mixed_outb.exp +++ b/testsuite/systemtap.printf/mixed_outb.exp @@ -16,7 +16,7 @@ if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} { } if {[catch {exec stap -DMAXACTION=100000 -b -o $tmpfile $test} res]} { - untested $TEST_NAME + fail $TEST_NAME puts "stap failed: $res" as_root "/bin/rm -f [glob ${tmpfile}*]" return diff --git a/testsuite/systemtap.printf/out1.exp b/testsuite/systemtap.printf/out1.exp index f89d39bf..d5728c0f 100644 --- a/testsuite/systemtap.printf/out1.exp +++ b/testsuite/systemtap.printf/out1.exp @@ -11,7 +11,7 @@ if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} { } if {[catch {exec stap -o $tmpfile $tpath} res]} { - untested $TEST_NAME + fail $TEST_NAME puts "$res" catch {exec rm -f $tmpfile} return diff --git a/testsuite/systemtap.printf/out1b.exp b/testsuite/systemtap.printf/out1b.exp index 378ea5cd..2f702a2f 100644 --- a/testsuite/systemtap.printf/out1b.exp +++ b/testsuite/systemtap.printf/out1b.exp @@ -16,7 +16,7 @@ if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} { } if {[catch {exec stap -b -o $tmpfile $test} res]} { - untested $TEST_NAME + fail $TEST_NAME puts "stap failed: $res" as_root "/bin/rm -f [glob ${tmpfile}*]" return diff --git a/testsuite/systemtap.printf/out2.exp b/testsuite/systemtap.printf/out2.exp index 7b312b11..dd96f394 100644 --- a/testsuite/systemtap.printf/out2.exp +++ b/testsuite/systemtap.printf/out2.exp @@ -11,7 +11,7 @@ if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} { } if {[catch {exec stap -o $tmpfile $tpath} res]} { - untested $TEST_NAME + fail $TEST_NAME puts "$res" catch {exec rm -f $tmpfile} return diff --git a/testsuite/systemtap.printf/out2b.exp b/testsuite/systemtap.printf/out2b.exp index f7fdef6b..0b56c940 100644 --- a/testsuite/systemtap.printf/out2b.exp +++ b/testsuite/systemtap.printf/out2b.exp @@ -16,7 +16,7 @@ if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} { } if {[catch {exec stap -b -o $tmpfile $test} res]} { - untested $TEST_NAME + fail $TEST_NAME puts "stap failed: $res" as_root "/bin/rm -f [glob ${tmpfile}*]" return diff --git a/testsuite/systemtap.printf/out3.exp b/testsuite/systemtap.printf/out3.exp index c16db391..96ca2bc5 100644 --- a/testsuite/systemtap.printf/out3.exp +++ b/testsuite/systemtap.printf/out3.exp @@ -11,7 +11,7 @@ if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} { } if {[catch {exec stap -DMAXACTION=100000 -o $tmpfile $tpath} res]} { - untested $TEST_NAME + fail $TEST_NAME puts "$res" catch {exec rm -f $tmpfile} return diff --git a/testsuite/systemtap.printf/out3b.exp b/testsuite/systemtap.printf/out3b.exp index 16ee2182..c42d03b7 100644 --- a/testsuite/systemtap.printf/out3b.exp +++ b/testsuite/systemtap.printf/out3b.exp @@ -16,7 +16,7 @@ if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} { } if {[catch {exec stap -DMAXACTION=100000 -b -o $tmpfile $test} res]} { - untested $TEST_NAME + fail $TEST_NAME puts "stap failed: $res" as_root "/bin/rm -f [glob ${tmpfile}*]" return -- 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/print_new.c | 2 +- runtime/transport/ring_buffer.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/runtime/print_new.c b/runtime/print_new.c index 4e579c37..4857b301 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -72,7 +72,7 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) uint32_t cnt; char *bufp = pb->buf; -#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 8) +#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) while (len > 0) { if (len > MAX_RESERVE_SIZE) { len -= MAX_RESERVE_SIZE; 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(-) 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(-) 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(-) 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(-) 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/print_new.c | 97 ++++++++++++++++++++++++++++++++++++++--- runtime/transport/ring_buffer.c | 8 +--- 2 files changed, 93 insertions(+), 12 deletions(-) diff --git a/runtime/print_new.c b/runtime/print_new.c index 4857b301..f8749842 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -33,15 +33,95 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) // if (unlikely(!_stp_utt || _stp_utt->trace_state != Utt_trace_running)) // return; +#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) #ifdef STP_BULKMODE { + struct _stp_entry *entry; #ifdef NO_PERCPU_HEADERS - void *buf = utt_reserve(_stp_utt, len); - if (likely(buf)) - memcpy(buf, pb->buf, len); - else - atomic_inc (&_stp_transport_failures); + { + uint32_t cnt; + char *bufp = pb->buf; + + printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", + __FUNCTION__, __LINE__, pb->len, len); + while (len > 0) { + if (len > MAX_RESERVE_SIZE) { + len -= MAX_RESERVE_SIZE; + cnt = MAX_RESERVE_SIZE; + } + else { + cnt = len; + len = 0; + } + + printk(KERN_ERR "%s:%d - reserving %d bytes\n", + __FUNCTION__, __LINE__, cnt); + entry = _stp_data_write_reserve(cnt); + if (likely(entry)) { + memcpy(entry->buf, bufp, cnt); + _stp_data_write_commit(entry); + bufp += cnt; + } + else { + atomic_inc (&_stp_transport_failures); + break; + } + } + } #else + +#undef MAX_RESERVE_SIZE +#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10 - sizeof(struct _stp_trace)) + { + uint32_t cnt; + char *bufp = pb->buf; + struct _stp_trace t = { .sequence = _stp_seq_inc(), + .pdu_len = len}; + + printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", + __FUNCTION__, __LINE__, pb->len, len); + + entry = _stp_data_write_reserve(sizeof(struct _stp_trace)); + if (likely(entry)) { + /* prevent unaligned access by using + * memcpy() */ + memcpy(entry->buf, &t, sizeof(t)); + _stp_data_write_commit(entry); + } + else { + atomic_inc (&_stp_transport_failures); + return; + } + + while (len > 0) { + if (len > MAX_RESERVE_SIZE) { + len -= MAX_RESERVE_SIZE; + cnt = MAX_RESERVE_SIZE; + } + else { + cnt = len; + len = 0; + } + + printk(KERN_ERR "%s:%d - reserving %d bytes\n", + __FUNCTION__, __LINE__, cnt); + entry = _stp_data_write_reserve(cnt); + if (likely(entry)) { + memcpy(entry->buf, bufp, cnt); + _stp_data_write_commit(entry); + bufp += cnt; + } + else { + atomic_inc (&_stp_transport_failures); + break; + } + } + } + + + + +#if 0 void *buf = utt_reserve(_stp_utt, sizeof(struct _stp_trace) + len); if (likely(buf)) { @@ -51,6 +131,7 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) memcpy(buf + sizeof(t), pb->buf, len); } else atomic_inc (&_stp_transport_failures); +#endif #endif } #else @@ -72,7 +153,9 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) uint32_t cnt; char *bufp = pb->buf; -#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) +//#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) + printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", + __FUNCTION__, __LINE__, pb->len, len); while (len > 0) { if (len > MAX_RESERVE_SIZE) { len -= MAX_RESERVE_SIZE; @@ -83,6 +166,8 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) len = 0; } + printk(KERN_ERR "%s:%d - reserving %d bytes\n", + __FUNCTION__, __LINE__, cnt); entry = _stp_data_write_reserve(cnt); if (likely(entry)) { memcpy(entry->buf, bufp, cnt); 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 8f47173deb9aa146b388542116d2638ed04fb03a Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 30 Mar 2009 15:12:27 -0500 Subject: 2009-03-30 David Smith * print_new.c: Whitespace/indent changes only. --- runtime/print_new.c | 168 ++++++++++++++++++++++++---------------------------- 1 file changed, 79 insertions(+), 89 deletions(-) diff --git a/runtime/print_new.c b/runtime/print_new.c index f8749842..01bbe809 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -21,6 +21,7 @@ static DEFINE_SPINLOCK(_stp_print_lock); void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) { uint32_t len = pb->len; + struct _stp_entry *entry; /* check to see if there is anything in the buffer */ dbug_trans(1, "len = %ud\n", len); @@ -35,125 +36,114 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) #define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) #ifdef STP_BULKMODE - { - struct _stp_entry *entry; #ifdef NO_PERCPU_HEADERS - { - uint32_t cnt; - char *bufp = pb->buf; - - printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", - __FUNCTION__, __LINE__, pb->len, len); - while (len > 0) { - if (len > MAX_RESERVE_SIZE) { - len -= MAX_RESERVE_SIZE; - cnt = MAX_RESERVE_SIZE; - } - else { - cnt = len; - len = 0; - } + { + uint32_t cnt; + char *bufp = pb->buf; + + printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", + __FUNCTION__, __LINE__, pb->len, len); + while (len > 0) { + if (len > MAX_RESERVE_SIZE) { + len -= MAX_RESERVE_SIZE; + cnt = MAX_RESERVE_SIZE; + } + else { + cnt = len; + len = 0; + } - printk(KERN_ERR "%s:%d - reserving %d bytes\n", - __FUNCTION__, __LINE__, cnt); - entry = _stp_data_write_reserve(cnt); - if (likely(entry)) { - memcpy(entry->buf, bufp, cnt); - _stp_data_write_commit(entry); - bufp += cnt; - } - else { - atomic_inc (&_stp_transport_failures); - break; - } + printk(KERN_ERR "%s:%d - reserving %d bytes\n", + __FUNCTION__, __LINE__, cnt); + entry = _stp_data_write_reserve(cnt); + if (likely(entry)) { + memcpy(entry->buf, bufp, cnt); + _stp_data_write_commit(entry); + bufp += cnt; + } + else { + atomic_inc (&_stp_transport_failures); + break; } } -#else + } + +#else /* !NO_PERCPU_HEADERS */ #undef MAX_RESERVE_SIZE #define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10 - sizeof(struct _stp_trace)) - { - uint32_t cnt; - char *bufp = pb->buf; - struct _stp_trace t = { .sequence = _stp_seq_inc(), - .pdu_len = len}; + { + uint32_t cnt; + char *bufp = pb->buf; + struct _stp_trace t = { .sequence = _stp_seq_inc(), + .pdu_len = len}; - printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", - __FUNCTION__, __LINE__, pb->len, len); + printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", + __FUNCTION__, __LINE__, pb->len, len); + + entry = _stp_data_write_reserve(sizeof(struct _stp_trace)); + if (likely(entry)) { + /* prevent unaligned access by using memcpy() */ + memcpy(entry->buf, &t, sizeof(t)); + _stp_data_write_commit(entry); + } + else { + atomic_inc (&_stp_transport_failures); + return; + } + + while (len > 0) { + if (len > MAX_RESERVE_SIZE) { + len -= MAX_RESERVE_SIZE; + cnt = MAX_RESERVE_SIZE; + } + else { + cnt = len; + len = 0; + } - entry = _stp_data_write_reserve(sizeof(struct _stp_trace)); + printk(KERN_ERR "%s:%d - reserving %d bytes\n", + __FUNCTION__, __LINE__, cnt); + entry = _stp_data_write_reserve(cnt); if (likely(entry)) { - /* prevent unaligned access by using - * memcpy() */ - memcpy(entry->buf, &t, sizeof(t)); + memcpy(entry->buf, bufp, cnt); _stp_data_write_commit(entry); + bufp += cnt; } else { atomic_inc (&_stp_transport_failures); - return; - } - - while (len > 0) { - if (len > MAX_RESERVE_SIZE) { - len -= MAX_RESERVE_SIZE; - cnt = MAX_RESERVE_SIZE; - } - else { - cnt = len; - len = 0; - } - - printk(KERN_ERR "%s:%d - reserving %d bytes\n", - __FUNCTION__, __LINE__, cnt); - entry = _stp_data_write_reserve(cnt); - if (likely(entry)) { - memcpy(entry->buf, bufp, cnt); - _stp_data_write_commit(entry); - bufp += cnt; - } - else { - atomic_inc (&_stp_transport_failures); - break; - } + break; } } + } #if 0 - void *buf = utt_reserve(_stp_utt, - sizeof(struct _stp_trace) + len); - if (likely(buf)) { - struct _stp_trace t = { .sequence = _stp_seq_inc(), - .pdu_len = len}; - memcpy(buf, &t, sizeof(t)); // prevent unaligned access - memcpy(buf + sizeof(t), pb->buf, len); - } else - atomic_inc (&_stp_transport_failures); -#endif + /* original code */ + void *buf = utt_reserve(_stp_utt, + sizeof(struct _stp_trace) + len); + if (likely(buf)) { + struct _stp_trace t = { .sequence = _stp_seq_inc(), + .pdu_len = len}; + memcpy(buf, &t, sizeof(t)); // prevent unaligned access + memcpy(buf + sizeof(t), pb->buf, len); + } else + atomic_inc (&_stp_transport_failures); #endif - } -#else + +#endif /* !NO_PERCPU_HEADERS */ +#else /* !STP_BULKMODE */ { - struct _stp_entry *entry; unsigned long flags; dbug_trans(1, "calling _stp_data_write...\n"); spin_lock_irqsave(&_stp_print_lock, flags); -#if 0 - entry = _stp_data_write_reserve(len); - if (likely(entry)) { - memcpy(entry->buf, pb->buf, len); - _stp_data_write_commit(entry); - } - else -#endif { uint32_t cnt; char *bufp = pb->buf; -//#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", __FUNCTION__, __LINE__, pb->len, len); while (len > 0) { @@ -182,5 +172,5 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) } spin_unlock_irqrestore(&_stp_print_lock, flags); } -#endif /* STP_BULKMODE */ +#endif /* !STP_BULKMODE */ } -- 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/print_new.c | 132 +++++++++++----------------------------- runtime/transport/ring_buffer.c | 34 ++++++++--- runtime/transport/transport.h | 3 +- 3 files changed, 64 insertions(+), 105 deletions(-) diff --git a/runtime/print_new.c b/runtime/print_new.c index 01bbe809..86c44ea7 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -18,14 +18,14 @@ static DEFINE_SPINLOCK(_stp_print_lock); -void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) +void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) { - uint32_t len = pb->len; - struct _stp_entry *entry; + size_t len = pb->len; + struct _stp_entry *entry = NULL; /* check to see if there is anything in the buffer */ - dbug_trans(1, "len = %ud\n", len); - if (likely (len == 0)) + dbug_trans(1, "len = %zu\n", len); + if (likely(len == 0)) return; pb->len = 0; @@ -34,35 +34,23 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) // if (unlikely(!_stp_utt || _stp_utt->trace_state != Utt_trace_running)) // return; -#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10) #ifdef STP_BULKMODE #ifdef NO_PERCPU_HEADERS { - uint32_t cnt; char *bufp = pb->buf; - printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", - __FUNCTION__, __LINE__, pb->len, len); while (len > 0) { - if (len > MAX_RESERVE_SIZE) { - len -= MAX_RESERVE_SIZE; - cnt = MAX_RESERVE_SIZE; - } - else { - cnt = len; - len = 0; - } + size_t bytes_reserved; - printk(KERN_ERR "%s:%d - reserving %d bytes\n", - __FUNCTION__, __LINE__, cnt); - entry = _stp_data_write_reserve(cnt); - if (likely(entry)) { - memcpy(entry->buf, bufp, cnt); + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(entry->buf, bufp, bytes_reserved); _stp_data_write_commit(entry); - bufp += cnt; + bufp += bytes_reserved; + len -= bytes_reserved; } else { - atomic_inc (&_stp_transport_failures); + atomic_inc(&_stp_transport_failures); break; } } @@ -70,104 +58,58 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) #else /* !NO_PERCPU_HEADERS */ -#undef MAX_RESERVE_SIZE -#define MAX_RESERVE_SIZE (4080 /*BUF_PAGE_SIZE*/ - sizeof(struct _stp_entry) - 10 - sizeof(struct _stp_trace)) { - uint32_t cnt; char *bufp = pb->buf; struct _stp_trace t = { .sequence = _stp_seq_inc(), .pdu_len = len}; + size_t bytes_reserved; - printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", - __FUNCTION__, __LINE__, pb->len, len); - - entry = _stp_data_write_reserve(sizeof(struct _stp_trace)); - if (likely(entry)) { + bytes_reserved = _stp_data_write_reserve(sizeof(struct _stp_trace), &entry); + if (likely(entry && bytes_reserved > 0)) { /* prevent unaligned access by using memcpy() */ memcpy(entry->buf, &t, sizeof(t)); _stp_data_write_commit(entry); } else { - atomic_inc (&_stp_transport_failures); + atomic_inc(&_stp_transport_failures); return; } while (len > 0) { - if (len > MAX_RESERVE_SIZE) { - len -= MAX_RESERVE_SIZE; - cnt = MAX_RESERVE_SIZE; - } - else { - cnt = len; - len = 0; - } - - printk(KERN_ERR "%s:%d - reserving %d bytes\n", - __FUNCTION__, __LINE__, cnt); - entry = _stp_data_write_reserve(cnt); - if (likely(entry)) { - memcpy(entry->buf, bufp, cnt); + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(entry->buf, bufp, bytes_reserved); _stp_data_write_commit(entry); - bufp += cnt; + bufp += bytes_reserved; + len -= bytes_reserved; } else { - atomic_inc (&_stp_transport_failures); + atomic_inc(&_stp_transport_failures); break; } } } - - - - -#if 0 - /* original code */ - void *buf = utt_reserve(_stp_utt, - sizeof(struct _stp_trace) + len); - if (likely(buf)) { - struct _stp_trace t = { .sequence = _stp_seq_inc(), - .pdu_len = len}; - memcpy(buf, &t, sizeof(t)); // prevent unaligned access - memcpy(buf + sizeof(t), pb->buf, len); - } else - atomic_inc (&_stp_transport_failures); -#endif - -#endif /* !NO_PERCPU_HEADERS */ -#else /* !STP_BULKMODE */ +#endif /* !NO_PERCPU_HEADERS */ +#else /* !STP_BULKMODE */ { unsigned long flags; + char *bufp = pb->buf; dbug_trans(1, "calling _stp_data_write...\n"); spin_lock_irqsave(&_stp_print_lock, flags); - { - uint32_t cnt; - char *bufp = pb->buf; - - printk(KERN_ERR "%s:%d - flushing %d(%d) bytes\n", - __FUNCTION__, __LINE__, pb->len, len); - while (len > 0) { - if (len > MAX_RESERVE_SIZE) { - len -= MAX_RESERVE_SIZE; - cnt = MAX_RESERVE_SIZE; - } - else { - cnt = len; - len = 0; - } + while (len > 0) { + size_t bytes_reserved; - printk(KERN_ERR "%s:%d - reserving %d bytes\n", - __FUNCTION__, __LINE__, cnt); - entry = _stp_data_write_reserve(cnt); - if (likely(entry)) { - memcpy(entry->buf, bufp, cnt); - _stp_data_write_commit(entry); - bufp += cnt; - } - else { - atomic_inc (&_stp_transport_failures); - break; - } + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(entry->buf, bufp, bytes_reserved); + _stp_data_write_commit(entry); + bufp += bytes_reserved; + len -= bytes_reserved; + } + else { + atomic_inc(&_stp_transport_failures); + break; } } spin_unlock_irqrestore(&_stp_print_lock, flags); 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) diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index feaa950c..7d1f5c5d 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -70,7 +70,8 @@ struct _stp_entry { char buf[]; }; -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); static int _stp_data_write_commit(struct _stp_entry *entry); #endif /* _TRANSPORT_TRANSPORT_H_ */ -- cgit From 9b23198d73b782bc05dc2b834c7db3afbdefda86 Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 2 Apr 2009 10:16:35 -0500 Subject: Renamed STP_OLD_TRANSPORT to STP_TRANSPORT_VERSION. 2009-04-02 David Smith * runtime.h: Defines STP_TRANSPORT_VERSION instead of STP_OLD_TRANSPORT. * staprun/staprun.h (STP_OLD_TRANSPORT): Ditto. * print.c: Changed STP_OLD_TRANSPORT to STP_TRANSPORT_VERSION. * staprun/mainloop.c (stp_main_loop): Ditto. * transport/transport.c: Ditto. * transport/transport.h: Ditto. * transport/transport_msgs.h: Ditto. * transport/utt.h: Ditto. --- runtime/print.c | 2 +- runtime/runtime.h | 7 ++++++- runtime/staprun/mainloop.c | 2 +- runtime/staprun/staprun.h | 5 +++-- runtime/transport/transport.c | 17 +++++++++++------ runtime/transport/transport.h | 2 +- runtime/transport/transport_msgs.h | 4 ++-- runtime/transport/utt.h | 2 +- 8 files changed, 26 insertions(+), 15 deletions(-) diff --git a/runtime/print.c b/runtime/print.c index fa517cb5..2e205f10 100644 --- a/runtime/print.c +++ b/runtime/print.c @@ -90,7 +90,7 @@ static void _stp_print_cleanup (void) /* The relayfs API changed between 2.6.15 and 2.6.16. */ /* Use the appropriate print flush function. */ -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 #include "print_old.c" #else #include "print_new.c" diff --git a/runtime/runtime.h b/runtime/runtime.h index 28283db6..78c27a84 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -34,9 +34,14 @@ #if !defined (CONFIG_DEBUG_FS) && !defined (CONFIG_DEBUG_FS_MODULE) #error "DebugFS is required and was not found in the kernel." #endif +#ifdef CONFIG_RING_BUFFER +#define STP_TRANSPORT_VERSION 3 +#else +#define STP_TRANSPORT_VERSION 2 +#endif #else /* older kernels have no debugfs and older version of relayfs. */ -#define STP_OLD_TRANSPORT +#define STP_TRANSPORT_VERSION 1 #endif #ifndef stp_for_each_cpu diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index 29eb4f1f..0745f611 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -452,7 +452,7 @@ int stp_main_loop(void) nb -= sizeof(uint32_t); switch (type) { -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 case STP_REALTIME_DATA: { ssize_t bw = write(out_fd[0], data, nb); diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index 84cf63fc..f49cc7db 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -90,8 +90,9 @@ extern char *__name__; /* Grabbed from linux/module.h kernel include. */ #define MODULE_NAME_LEN (64 - sizeof(unsigned long)) -/* we define this so we are compatible with old transport, but we don't have to use it. */ -#define STP_OLD_TRANSPORT +/* We define this so we are compatible with old transport, but we + * don't have to use it. */ +#define STP_TRANSPORT_VERSION 1 #include "../transport/transport_msgs.h" #define RELAYFS_MAGIC 0xF0B4A981 diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index c4c9da1e..c0c97467 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -41,12 +41,17 @@ static int _stp_probes_started = 0; static struct utt_trace *_stp_utt = NULL; static unsigned int utt_seq = 1; #include "control.h" -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 #include "relayfs.c" #include "procfs.c" -#else +#elif STP_TRANSPORT_VERSION == 2 #include "utt.c" #include "debugfs.c" +#elif STP_TRANSPORT_VERSION == 3 +#include "debugfs.c" +#include "ring_buffer.c" +#else +#error "Unknown STP_TRANSPORT_VERSION" #endif #include "control.c" @@ -355,7 +360,7 @@ static struct dentry *_stp_lockfile = NULL; static int _stp_lock_transport_dir(void) { int numtries = 0; -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 while ((_stp_lockfile = relayfs_create_dir("systemtap_lock", NULL)) == NULL) { #else while ((_stp_lockfile = debugfs_create_dir("systemtap_lock", NULL)) == NULL) { @@ -370,7 +375,7 @@ static int _stp_lock_transport_dir(void) static void _stp_unlock_transport_dir(void) { if (_stp_lockfile) { -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 relayfs_remove_dir(_stp_lockfile); #else debugfs_remove(_stp_lockfile); @@ -394,7 +399,7 @@ static struct dentry *_stp_get_root_dir(void) return __stp_root_dir; } -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 fs = get_fs_type("relayfs"); if (!fs) { errk("Couldn't find relayfs filesystem.\n"); @@ -412,7 +417,7 @@ static struct dentry *_stp_get_root_dir(void) errk("Couldn't lock transport directory.\n"); return NULL; } -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 __stp_root_dir = relayfs_create_dir(name, NULL); #else __stp_root_dir = debugfs_create_dir(name, NULL); diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index 7d1f5c5d..1d245cc6 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -26,7 +26,7 @@ static inline void *utt_reserve(struct utt_trace *utt, size_t length) /* STP_CTL_BUFFER_SIZE is the maximum size of a message */ /* exchanged on the control channel. */ -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 /* Old transport sends print output on control channel */ #define STP_CTL_BUFFER_SIZE STP_BUFFER_SIZE #else diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h index 596f4925..0d6853f7 100644 --- a/runtime/transport/transport_msgs.h +++ b/runtime/transport/transport_msgs.h @@ -30,7 +30,7 @@ enum STP_BULK, STP_READY, STP_RELOCATION, - /** deprecated STP_OLD_TRANSPORT **/ + /** deprecated STP_TRANSPORT_VERSION == 1 **/ STP_BUF_INFO, STP_SUBBUFS_CONSUMED, STP_REALTIME_DATA, @@ -81,7 +81,7 @@ struct _stp_msg_start int32_t res; // for reply: result of probe_start() }; -#ifdef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 1 /**** for compatibility with old relayfs ****/ struct _stp_buf_info { diff --git a/runtime/transport/utt.h b/runtime/transport/utt.h index 0a0944c0..2a479d70 100644 --- a/runtime/transport/utt.h +++ b/runtime/transport/utt.h @@ -47,7 +47,7 @@ static int utt_trace_startstop(struct utt_trace *utt, int start, static void utt_trace_cleanup(struct utt_trace *utt); static int utt_trace_remove(struct utt_trace *utt); -#ifndef STP_OLD_TRANSPORT +#if STP_TRANSPORT_VERSION == 2 static size_t utt_switch_subbuf(struct utt_trace *utt, struct rchan_buf *buf, size_t length); /** -- 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/control.c | 1 + runtime/transport/relay_v2.c | 550 ++++++++++++++++++++++++++++++++++++++++ runtime/transport/ring_buffer.c | 51 +--- runtime/transport/transport.c | 22 +- 4 files changed, 573 insertions(+), 51 deletions(-) create mode 100644 runtime/transport/relay_v2.c diff --git a/runtime/transport/control.c b/runtime/transport/control.c index 7626305a..4e07a0a7 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -12,6 +12,7 @@ #include "control.h" #include "../mempool.c" #include "symbols.c" +#include static _stp_mempool_t *_stp_pool_q; static struct list_head _stp_ctl_ready_q; diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c new file mode 100644 index 00000000..771a3a3c --- /dev/null +++ b/runtime/transport/relay_v2.c @@ -0,0 +1,550 @@ +#include +#include +#include +#include +#if 0 +#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 + * 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; +#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; +} + +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; + } + /* 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) + goto fail; + + dbug_trans(1, "size = %lu\n", ring_buffer_size(__stp_ring_buffer)); + return 0; + +fail: + __stp_free_ring_buffer(); + return -ENOMEM; +} + +static int _stp_data_open_trace(struct inode *inode, struct file *file) +{ + long cpu_file = (long) inode->i_private; + + /* 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); + 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 + file->private_data = inode->i_private; + 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"); +#ifdef STP_BULKMODE + cpumask_clear_cpu(cpu_file, _stp_trace_reader_cpumask); +#else + cpumask_clear(_stp_trace_reader_cpumask); +#endif + + return 0; +} + +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 ssize_t tracing_wait_pipe(struct file *filp) +{ + while (ring_buffer_empty(__stp_ring_buffer)) { + + if ((filp->f_flags & O_NONBLOCK)) { + dbug_trans(1, "returning -EAGAIN\n"); + 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)) { + dbug_trans(1, "returning -EINTR\n"); + return -EINTR; + } + } + + 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 * +__stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) +{ + 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(__stp_ring_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; + + 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; +#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. + */ +static ssize_t +_stp_data_read_trace(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + ssize_t sret; + struct _stp_entry *entry; + long cpu_file = (long) filp->private_data; + + dbug_trans(1, "%lu\n", (unsigned long)cnt); + + 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 (ring_buffer_empty(__stp_ring_buffer)) { + sret = 0; + goto out; + } + + if (cnt >= PAGE_SIZE) + cnt = PAGE_SIZE - 1; + + dbug_trans(1, "sret = %lu\n", (unsigned long)sret); + sret = 0; + while ((entry = _stp_find_next_entry(cpu_file)) != NULL) { + ssize_t len; + + len = _stp_entry_to_user(entry, ubuf, cnt); + if (len <= 0) + break; + + ring_buffer_consume(__stp_ring_buffer, _stp_iter.cpu, + &_stp_iter.ts); + ubuf += len; + cnt -= len; + sret += len; + if (cnt <= 0) + break; + } +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, + .poll = _stp_data_poll_trace, + .read = _stp_data_read_trace, +#if 0 + .splice_read = tracing_splice_read_pipe, +#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. + * + * 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 size_t +_stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) +{ + struct ring_buffer_event *event; + + 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_request), + 0); + if (unlikely(! event)) { + dbug_trans(1, "event = NULL (%p)?\n", event); + entry = NULL; + return 0; + } + + *entry = ring_buffer_event_data(event); + (*entry)->event = event; + (*entry)->len = size_request; + return size_request; +} +#endif + +static int _stp_data_write_commit(struct _stp_entry *entry) +{ +#if 0 + int ret; + + if (unlikely(! entry)) { + dbug_trans(1, "entry = NULL, returning -EINVAL\n"); + return -EINVAL; + } + + 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)); + + wake_up_interruptible(&_stp_poll_wait); + return ret; +#else + return 0; +#endif +} + + +#if 0 +static struct dentry *__stp_entry[NR_CPUS] = { NULL }; +#endif + + + +struct _stp_relay_data { + struct rchan *rchan; + int overwrite_flag; +}; +static struct _stp_relay_data _stp_relay; + + + +static size_t utt_switch_subbuf(struct utt_trace *utt, struct rchan_buf *buf, + size_t length); +/** + * utt_reserve - reserve slot in channel buffer + * @utt: utt channel + * @length: number of bytes to reserve + * + * Returns pointer to reserved slot, NULL if full. + * + * This function is utt_switch_subbuf version of relay_reserve. + */ +static size_t +_stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) +{ +#if 0 + void *reserved; + struct rchan_buf *buf = utt->rchan->buf[smp_processor_id()]; + + if (unlikely(buf->offset + length > buf->chan->subbuf_size)) { + length = utt_switch_subbuf(utt, buf, length); + if (!length) + return NULL; + } + reserved = (char*)buf->data + buf->offset; + buf->offset += length; + + return reserved; +#else + return 0; +#endif +} + + + + +static int +_stp_relay_subbuf_start_callback(struct rchan_buf *buf, void *subbuf, + void *prev_subbuf, size_t prev_padding) +{ + if (_stp_relay.overwrite_flag || !relay_buf_full(buf)) + return 1; + + return 0; +} + +static struct dentry * +_stp_relay_create_buf_file_callback(const char *filename, + struct dentry *parent, + int mode, + struct rchan_buf *buf, + int *is_global) +{ + struct dentry *file; + + if (is_global) { +#ifdef STP_BULKMODE + *is_global = 0; +#else + *is_global = 1; +#endif + } + + file = debugfs_create_file(filename, mode, parent, buf, + &relay_file_operations); + if (file) { + file->d_inode->i_uid = _stp_uid; + file->d_inode->i_gid = _stp_gid; + } + return file; +} + +static int +_stp_relay_remove_buf_file_callback(struct dentry *dentry) +{ + debugfs_remove(dentry); + return 0; +} + +static struct rchan_callbacks _stp_relay_callbacks = { + .subbuf_start = _stp_relay_subbuf_start_callback, + .create_buf_file = _stp_relay_create_buf_file_callback, + .remove_buf_file = _stp_relay_remove_buf_file_callback, +}; + +static int _stp_transport_data_fs_init(void) +{ + int rc; + u64 npages; + struct sysinfo si; + + _stp_relay.overwrite_flag = 0; + + npages = _stp_subbuf_size * _stp_nsubbufs; +#ifdef STP_BULKMODE + npages *= num_possible_cpus(); +#endif + npages >>= PAGE_SHIFT; + si_meminfo(&si); +#define MB(i) (unsigned long)((i) >> (20 - PAGE_SHIFT)) + if (npages > (si.freeram + si.bufferram)) { + errk("Not enough free+buffered memory(%luMB) for log buffer(%luMB)\n", + MB(si.freeram + si.bufferram), + MB(npages)); + rc = -ENOMEM; + goto err; + } + else if (npages > si.freeram) { + /* exceeds freeram, but below freeram+bufferram */ + printk(KERN_WARNING + "log buffer size exceeds free memory(%luMB)\n", + MB(si.freeram)); + } + +#if (RELAYFS_CHANNEL_VERSION >= 7) + _stp_relay.rchan = relay_open("trace", _stp_get_module_dir(), + _stp_subbuf_size, _stp_nsubbufs, + &_stp_relay_callbacks, NULL); +#else /* (RELAYFS_CHANNEL_VERSION < 7) */ + _stp_relay.rchan = relay_open("trace", _stp_get_module_dir(), + _stp_subbuf_size, _stp_nsubbufs, + &_stp_relay_callbacks); +#endif /* (RELAYFS_CHANNEL_VERSION < 7) */ + + if (!_stp_relay.rchan) { + rc = -ENOENT; + goto err; + } + dbug_trans(1, "returning 0...\n"); + return 0; + +err: + if (_stp_relay.rchan) + relay_close(_stp_relay.rchan); + return rc; +} + +static void _stp_transport_data_fs_close(void) +{ + if (_stp_relay.rchan) + relay_close(_stp_relay.rchan); +} + 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; diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index c0c97467..5a499e8d 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -18,11 +18,14 @@ #include #include #include +#include +#if 0 static void utt_set_overwrite(int overwrite) { return; } +#endif static int _stp_exit_flag = 0; @@ -35,21 +38,19 @@ static int _stp_ctl_attached = 0; static pid_t _stp_target = 0; static int _stp_probes_started = 0; -#if 0 -#include - -static struct utt_trace *_stp_utt = NULL; -static unsigned int utt_seq = 1; +#if 1 +//static struct utt_trace *_stp_utt = NULL; +//static unsigned int utt_seq = 1; #include "control.h" #if STP_TRANSPORT_VERSION == 1 #include "relayfs.c" #include "procfs.c" #elif STP_TRANSPORT_VERSION == 2 -#include "utt.c" +#include "relay_v2.c" #include "debugfs.c" #elif STP_TRANSPORT_VERSION == 3 -#include "debugfs.c" #include "ring_buffer.c" +#include "debugfs.c" #else #error "Unknown STP_TRANSPORT_VERSION" #endif @@ -59,7 +60,6 @@ static unsigned int utt_seq = 1; #include "control.h" #include "debugfs.c" #include "control.c" -#include "ring_buffer.c" #endif /* if 0 */ static unsigned _stp_nsubbufs = 8; static unsigned _stp_subbuf_size = 65536*4; @@ -158,8 +158,10 @@ static void _stp_detach(void) _stp_ctl_attached = 0; _stp_pid = 0; +#if 0 if (!_stp_exit_flag) utt_set_overwrite(1); +#endif cancel_delayed_work(&_stp_work); wake_up_interruptible(&_stp_ctl_wq); @@ -173,7 +175,9 @@ static void _stp_attach(void) dbug_trans(1, "attach\n"); _stp_ctl_attached = 1; _stp_pid = current->pid; +#if 0 utt_set_overwrite(0); +#endif queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); } @@ -458,7 +462,7 @@ static void _stp_remove_root_dir(void) static struct dentry *__stp_module_dir = NULL; -static inline struct dentry *_stp_get_module_dir(void) +static struct dentry *_stp_get_module_dir(void) { return __stp_module_dir; } -- cgit From 09334fd8db6c57743a7da34dd55be551fef6e39f Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 6 May 2009 14:32:08 -0500 Subject: Added comments. * runtime/transport/transport.h: Added comments. --- runtime/transport/transport.h | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index 1d245cc6..8ab65dec 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -61,7 +61,25 @@ static gid_t _stp_gid; static int _stp_ctl_attached; static int _stp_bufsize; + +/* + * All transports must provide the following functions. + */ + +/* + * _stp_transport_data_fs_init + * + * This function allocates any buffers needed, creates files, + * etc. needed for this transport. + */ static int _stp_transport_data_fs_init(void); + +/* + * _stp_transport_data_fs_close + * + * This function cleans up items created by + * _stp_transport_data_fs_init(). + */ static void _stp_transport_data_fs_close(void); struct _stp_entry { @@ -70,8 +88,27 @@ struct _stp_entry { char buf[]; }; +/* + * _stp_data_write_reserve - reserve bytes + * size_request: number of bytes to reserve + * entry: allocated buffer is returned here + * + * This function attempts to reserve size_request number of bytes, + * returning the number of bytes actually reserved. The allocated + * buffer is returned in entry. Note that the number of bytes + * allocated may be less than the number of bytes requested. + */ static size_t _stp_data_write_reserve(size_t size_request, struct _stp_entry **entry); + +/* + * _stp_data_write_commit - + * entry: _stp_entry returned by + * _stp-data_write_reserve() + * + * This function notifies the transport that the bytes in entry are + * ready to be written. + */ static int _stp_data_write_commit(struct _stp_entry *entry); #endif /* _TRANSPORT_TRANSPORT_H_ */ -- 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/print_new.c | 13 +++--- runtime/transport/ring_buffer.c | 95 +++++++++++++++++++++++++---------------- runtime/transport/transport.h | 23 +++++----- 3 files changed, 79 insertions(+), 52 deletions(-) diff --git a/runtime/print_new.c b/runtime/print_new.c index 86c44ea7..b6187978 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -21,7 +21,7 @@ static DEFINE_SPINLOCK(_stp_print_lock); void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) { size_t len = pb->len; - struct _stp_entry *entry = NULL; + void *entry = NULL; /* check to see if there is anything in the buffer */ dbug_trans(1, "len = %zu\n", len); @@ -44,7 +44,8 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) bytes_reserved = _stp_data_write_reserve(len, &entry); if (likely(entry && bytes_reserved > 0)) { - memcpy(entry->buf, bufp, bytes_reserved); + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); _stp_data_write_commit(entry); bufp += bytes_reserved; len -= bytes_reserved; @@ -67,7 +68,7 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) bytes_reserved = _stp_data_write_reserve(sizeof(struct _stp_trace), &entry); if (likely(entry && bytes_reserved > 0)) { /* prevent unaligned access by using memcpy() */ - memcpy(entry->buf, &t, sizeof(t)); + memcpy(_stp_data_entry_data(entry), &t, sizeof(t)); _stp_data_write_commit(entry); } else { @@ -78,7 +79,8 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) while (len > 0) { bytes_reserved = _stp_data_write_reserve(len, &entry); if (likely(entry && bytes_reserved > 0)) { - memcpy(entry->buf, bufp, bytes_reserved); + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); _stp_data_write_commit(entry); bufp += bytes_reserved; len -= bytes_reserved; @@ -102,7 +104,8 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) bytes_reserved = _stp_data_write_reserve(len, &entry); if (likely(entry && bytes_reserved > 0)) { - memcpy(entry->buf, bufp, bytes_reserved); + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); _stp_data_write_commit(entry); bufp += bytes_reserved; len -= bytes_reserved; 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)); diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index 8ab65dec..c560be5d 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -82,12 +82,6 @@ static int _stp_transport_data_fs_init(void); */ static void _stp_transport_data_fs_close(void); -struct _stp_entry { - void *event; - size_t len; - char buf[]; -}; - /* * _stp_data_write_reserve - reserve bytes * size_request: number of bytes to reserve @@ -98,17 +92,24 @@ struct _stp_entry { * buffer is returned in entry. Note that the number of bytes * allocated may be less than the number of bytes requested. */ -static size_t _stp_data_write_reserve(size_t size_request, - struct _stp_entry **entry); +static size_t _stp_data_write_reserve(size_t size_request, void **entry); + + +/* + * _stp_data_entry_data - return data pointer from entry + * entry: entry + * + * This function returns the data pointer from entry. + */ +static unsigned char *_stp_data_entry_data(void *entry); /* * _stp_data_write_commit - - * entry: _stp_entry returned by - * _stp-data_write_reserve() + * entry: pointer returned by _stp-data_write_reserve() * * This function notifies the transport that the bytes in entry are * ready to be written. */ -static int _stp_data_write_commit(struct _stp_entry *entry); +static int _stp_data_write_commit(void *entry); #endif /* _TRANSPORT_TRANSPORT_H_ */ -- cgit From b47be87f5bcab55ed08cbfb07f0a39447f3f81ed Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 8 May 2009 15:00:06 -0500 Subject: Working transport version 2 (RHEL5 and recent fedora kernels). * runtime/transport/relay_v2.c: Morphed utt.c into relay_v2.c. Actually works. --- runtime/transport/relay_v2.c | 790 ++++++++++++++++++++----------------------- 1 file changed, 376 insertions(+), 414 deletions(-) diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index 771a3a3c..ea4d9241 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -1,503 +1,427 @@ -#include +/* -*- linux-c -*- + * + * This is a modified version of the proposed utt interface. If that + * interface makes it into the kernel, this file can go away. + * + * Copyright (C) 2006 Jens Axboe + * + * Moved to utt.c by Tom Zanussi, 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ #include -#include +#include +#include +#include #include -#if 0 -#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); +#include +#include +#include -#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; +#ifndef STP_RELAY_TIMER_INTERVAL +/* Wakeup timer interval in jiffies (default 10 ms) */ +#define STP_RELAY_TIMER_INTERVAL ((HZ + 99) / 100) #endif - int cpu; - u64 ts; - -#if 0 - unsigned long iter_flags; - loff_t pos; - long idx; - cpumask_var_t started; -#endif +enum _stp_transport_state { + STP_TRANSPORT_STOPPED, + STP_TRANSPORT_INITIALIZED, + STP_TRANSPORT_RUNNING, }; -static struct _stp_ring_buffer_iterator _stp_iter; -#endif -static cpumask_var_t _stp_trace_reader_cpumask; +struct _stp_relay_data_type { + enum _stp_transport_state transport_state; + struct rchan *rchan; + struct dentry *dir; /* systemtap/module_name */ + struct dentry *dropped_file; + atomic_t dropped; + struct dentry *utt_tree_root; /* systemtap */ + atomic_t wakeup; + struct timer_list timer; + int overwrite_flag; +}; +struct _stp_relay_data_type _stp_relay_data; -static void __stp_free_ring_buffer(void) +/* + * __stp_relay_switch_subbuf - switch to a new sub-buffer + * + * Most of this function is deadcopy of relay_switch_subbuf. + */ +static size_t __stp_relay_switch_subbuf(struct rchan_buf *buf, size_t length) { - free_cpumask_var(_stp_trace_reader_cpumask); - if (__stp_ring_buffer) - ring_buffer_free(__stp_ring_buffer); - __stp_ring_buffer = NULL; -} + char *old, *new; + size_t old_subbuf, new_subbuf; -static int __stp_alloc_ring_buffer(void) -{ - int i; - unsigned long buffer_size = _stp_bufsize; + if (unlikely(buf == NULL)) + return 0; - if (!alloc_cpumask_var(&_stp_trace_reader_cpumask, GFP_KERNEL)) - goto fail; - cpumask_clear(_stp_trace_reader_cpumask); + if (unlikely(length > buf->chan->subbuf_size)) + goto toobig; + + if (buf->offset != buf->chan->subbuf_size + 1) { + buf->prev_padding = buf->chan->subbuf_size - buf->offset; + old_subbuf = buf->subbufs_produced % buf->chan->n_subbufs; + buf->padding[old_subbuf] = buf->prev_padding; + buf->subbufs_produced++; + buf->dentry->d_inode->i_size += buf->chan->subbuf_size - + buf->padding[old_subbuf]; + smp_mb(); + if (waitqueue_active(&buf->read_wait)) + /* + * Calling wake_up_interruptible() and __mod_timer() + * from here will deadlock if we happen to be logging + * from the scheduler and timer (trying to re-grab + * rq->lock/timer->base->lock), so just set a flag. + */ + atomic_set(&_stp_relay_data.wakeup, 1); + } - if (buffer_size == 0) { - dbug_trans(1, "using default buffer size...\n"); - buffer_size = _stp_nsubbufs * _stp_subbuf_size; + old = buf->data; + new_subbuf = buf->subbufs_produced % buf->chan->n_subbufs; + new = (char*)buf->start + new_subbuf * buf->chan->subbuf_size; + buf->offset = 0; + if (!buf->chan->cb->subbuf_start(buf, new, old, buf->prev_padding)) { + buf->offset = buf->chan->subbuf_size + 1; + return 0; } - /* 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) - goto fail; - - dbug_trans(1, "size = %lu\n", ring_buffer_size(__stp_ring_buffer)); - return 0; + buf->data = new; + buf->padding[new_subbuf] = 0; + + if (unlikely(length + buf->offset > buf->chan->subbuf_size)) + goto toobig; + + return length; -fail: - __stp_free_ring_buffer(); - return -ENOMEM; +toobig: + buf->chan->last_toobig = length; + return 0; } -static int _stp_data_open_trace(struct inode *inode, struct file *file) +static void __stp_relay_wakeup_readers(struct rchan_buf *buf) { - long cpu_file = (long) inode->i_private; + if (buf && waitqueue_active(&buf->read_wait) && + buf->subbufs_produced != buf->subbufs_consumed) + wake_up_interruptible(&buf->read_wait); +} - /* We only allow for one reader per cpu */ - dbug_trans(1, "trace attach\n"); +static void __stp_relay_wakeup_timer(unsigned long val) +{ #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); + int i; #endif - file->private_data = inode->i_private; - 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"); + if (atomic_read(&_stp_relay_data.wakeup)) { + atomic_set(&_stp_relay_data.wakeup, 0); #ifdef STP_BULKMODE - cpumask_clear_cpu(cpu_file, _stp_trace_reader_cpumask); + for_each_possible_cpu(i) + __stp_relay_wakeup_readers(_stp_relay_data.rchan->buf[i]); #else - cpumask_clear(_stp_trace_reader_cpumask); + __stp_relay_wakeup_readers(_stp_relay_data.rchan->buf[0]); #endif + } - return 0; + mod_timer(&_stp_relay_data.timer, jiffies + STP_RELAY_TIMER_INTERVAL); } -size_t -_stp_entry_to_user(struct _stp_entry *entry, char __user *ubuf, size_t cnt) +static void __stp_relay_timer_init(void) { - 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; + atomic_set(&_stp_relay_data.wakeup, 0); + init_timer(&_stp_relay_data.timer); + _stp_relay_data.timer.expires = jiffies + STP_RELAY_TIMER_INTERVAL; + _stp_relay_data.timer.function = __stp_relay_wakeup_timer; + _stp_relay_data.timer.data = 0; + add_timer(&_stp_relay_data.timer); + smp_mb(); } -static ssize_t tracing_wait_pipe(struct file *filp) +static void stp_relay_set_overwrite(int overwrite) { - while (ring_buffer_empty(__stp_ring_buffer)) { - - if ((filp->f_flags & O_NONBLOCK)) { - dbug_trans(1, "returning -EAGAIN\n"); - return -EAGAIN; - } + _stp_relay_data.overwrite_flag = overwrite; +} - /* - * 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)) { - dbug_trans(1, "returning -EINTR\n"); - return -EINTR; +static void __stp_relay_remove_root(void) +{ + if (_stp_relay_data.utt_tree_root) { + if (!_stp_lock_transport_dir()) { + errk("Unable to lock transport directory.\n"); + return; } + if (simple_empty(_stp_relay_data.utt_tree_root)) + debugfs_remove(_stp_relay_data.utt_tree_root); + _stp_unlock_transport_dir(); + _stp_relay_data.utt_tree_root = NULL; } - - dbug_trans(1, "returning 1\n"); - return 1; } -static struct _stp_entry * -peek_next_entry(int cpu, u64 *ts) +static void __stp_relay_remove_tree(void) { - struct ring_buffer_event *event; - - event = ring_buffer_peek(__stp_ring_buffer, cpu, ts); - - return event ? ring_buffer_event_data(event) : NULL; + if (_stp_relay_data.dir == NULL) + return; + debugfs_remove(_stp_relay_data.dir); + __stp_relay_remove_root(); } -static struct _stp_entry * -__stp_find_next_entry(long cpu_file, int *ent_cpu, u64 *ent_ts) +static struct dentry *__stp_relay_create_tree(const char *root, + const char *name) { - struct _stp_entry *ent; + struct dentry *dir = NULL; -#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(__stp_ring_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; - - for_each_possible_cpu(cpu) { - - if (ring_buffer_empty_cpu(__stp_ring_buffer, cpu)) - continue; + if (root == NULL || name == NULL) + return NULL; - ent = peek_next_entry(cpu, &ts); + if (!_stp_relay_data.utt_tree_root) { + _stp_relay_data.utt_tree_root = _stp_get_root_dir(); + if (!_stp_relay_data.utt_tree_root) + goto err; + } - /* - * 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; -#endif + dir = debugfs_create_dir(name, _stp_relay_data.utt_tree_root); + if (!dir) + __stp_relay_remove_root(); +err: + return dir; } -/* Find the next real entry, and increment the iterator to the next entry */ -static struct _stp_entry *_stp_find_next_entry(long cpu_file) +static void __stp_relay_cleanup(void) { - return __stp_find_next_entry(cpu_file, &_stp_iter.cpu, &_stp_iter.ts); + if (_stp_relay_data.rchan) + relay_close(_stp_relay_data.rchan); + if (_stp_relay_data.dropped_file) + debugfs_remove(_stp_relay_data.dropped_file); + __stp_relay_remove_tree(); } - -/* - * Consumer reader. - */ -static ssize_t -_stp_data_read_trace(struct file *filp, char __user *ubuf, - size_t cnt, loff_t *ppos) +static int _stp_relay_remove(void) { - ssize_t sret; - struct _stp_entry *entry; - long cpu_file = (long) filp->private_data; - - dbug_trans(1, "%lu\n", (unsigned long)cnt); - - 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 (ring_buffer_empty(__stp_ring_buffer)) { - sret = 0; - goto out; - } + if (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED || + _stp_relay_data.transport_state == STP_TRANSPORT_STOPPED) + __stp_relay_cleanup(); - if (cnt >= PAGE_SIZE) - cnt = PAGE_SIZE - 1; - - dbug_trans(1, "sret = %lu\n", (unsigned long)sret); - sret = 0; - while ((entry = _stp_find_next_entry(cpu_file)) != NULL) { - ssize_t len; - - len = _stp_entry_to_user(entry, ubuf, cnt); - if (len <= 0) - break; - - ring_buffer_consume(__stp_ring_buffer, _stp_iter.cpu, - &_stp_iter.ts); - ubuf += len; - cnt -= len; - sret += len; - if (cnt <= 0) - break; - } -out: - return sret; + return 0; } - -static unsigned int -_stp_data_poll_trace(struct file *filp, poll_table *poll_table) +static int __stp_relay_dropped_open(struct inode *inode, struct file *filp) { - 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, - .poll = _stp_data_poll_trace, - .read = _stp_data_read_trace, -#if 0 - .splice_read = tracing_splice_read_pipe, -#endif -}; +static ssize_t __stp_relay_dropped_read(struct file *filp, char __user *buffer, + size_t count, loff_t *ppos) +{ + char buf[16]; -/* 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)) + snprintf(buf, sizeof(buf), "%u\n", + atomic_read(&_stp_relay_data.dropped)); + + return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); +} + +static struct file_operations __stp_relay_dropped_fops = { + .owner = THIS_MODULE, + .open = __stp_relay_dropped_open, + .read = __stp_relay_dropped_read, +}; /* - * 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. - * + * Keep track of how many times we encountered a full subbuffer, to aid + * the user space app in telling how many lost events there were. */ -static size_t -_stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) +static int __stp_relay_subbuf_start_callback(struct rchan_buf *buf, + void *subbuf, void *prev_subbuf, + size_t prev_padding) { - struct ring_buffer_event *event; - - 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_request), - 0); - if (unlikely(! event)) { - dbug_trans(1, "event = NULL (%p)?\n", event); - entry = NULL; - return 0; - } + if (_stp_relay_data.overwrite_flag || !relay_buf_full(buf)) + return 1; - *entry = ring_buffer_event_data(event); - (*entry)->event = event; - (*entry)->len = size_request; - return size_request; + atomic_inc(&_stp_relay_data.dropped); + return 0; } -#endif -static int _stp_data_write_commit(struct _stp_entry *entry) +static int __stp_relay_remove_buf_file_callback(struct dentry *dentry) { -#if 0 - int ret; + debugfs_remove(dentry); + return 0; +} - if (unlikely(! entry)) { - dbug_trans(1, "entry = NULL, returning -EINVAL\n"); - return -EINVAL; +static struct dentry * +__stp_relay_create_buf_file_callback(const char *filename, + struct dentry *parent, + int mode, + struct rchan_buf *buf, + int *is_global) +{ + struct dentry *file = debugfs_create_file(filename, mode, parent, buf, + &relay_file_operations); + if (file) { + file->d_inode->i_uid = _stp_uid; + file->d_inode->i_gid = _stp_gid; } - - 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)); - - wake_up_interruptible(&_stp_poll_wait); - return ret; -#else - return 0; -#endif + return file; } +static struct rchan_callbacks __stp_relay_callbacks = { + .subbuf_start = __stp_relay_subbuf_start_callback, + .create_buf_file = __stp_relay_create_buf_file_callback, + .remove_buf_file = __stp_relay_remove_buf_file_callback, +}; #if 0 -static struct dentry *__stp_entry[NR_CPUS] = { NULL }; -#endif - - - -struct _stp_relay_data { - struct rchan *rchan; - int overwrite_flag; -}; -static struct _stp_relay_data _stp_relay; +/* + * Setup everything required to start tracing + */ +static struct _stp_relay_data_type *utt_trace_setup(struct utt_trace_setup *utts) +{ + struct dentry *dir = NULL; + int ret = -EINVAL; + u64 npages; + struct sysinfo si; + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + _stp_relay_data.overwrite_flag = 0; + if (!utts->buf_size || !utts->buf_nr) + goto err; -static size_t utt_switch_subbuf(struct utt_trace *utt, struct rchan_buf *buf, - size_t length); -/** - * utt_reserve - reserve slot in channel buffer - * @utt: utt channel - * @length: number of bytes to reserve - * - * Returns pointer to reserved slot, NULL if full. - * - * This function is utt_switch_subbuf version of relay_reserve. - */ -static size_t -_stp_data_write_reserve(size_t size_request, struct _stp_entry **entry) -{ -#if 0 - void *reserved; - struct rchan_buf *buf = utt->rchan->buf[smp_processor_id()]; + ret = -ENOENT; + dir = __stp_relay_create_tree(utts->root, utts->name); + if (!dir) + goto err; + _stp_relay_data.dir = dir; + atomic_set(&_stp_relay_data.dropped, 0); + + ret = -EIO; + _stp_relay_data.dropped_file = debugfs_create_file("dropped", 0444, + dir, NULL, + &__stp_relay_dropped_fops); + if (!_stp_relay_data.dropped_file) + goto err; - if (unlikely(buf->offset + length > buf->chan->subbuf_size)) { - length = utt_switch_subbuf(utt, buf, length); - if (!length) - return NULL; + npages = utts->buf_size * utts->buf_nr; +#ifndef STP_BULKMODE + npages *= num_possible_cpus(); +#endif + npages >>= PAGE_SHIFT; + si_meminfo(&si); +#define MB(i) (unsigned long)((i) >> (20 - PAGE_SHIFT)) + if (npages > (si.freeram + si.bufferram)) { + errk("Not enough free+buffered memory(%luMB) for log buffer(%luMB)\n", + MB(si.freeram + si.bufferram), + MB(npages)); + ret = -ENOMEM; + goto err; + } else if (npages > si.freeram) { + /* exceeds freeram, but below freeram+bufferram */ + printk(KERN_WARNING + "log buffer size exceeds free memory(%luMB)\n", + MB(si.freeram)); } - reserved = (char*)buf->data + buf->offset; - buf->offset += length; - return reserved; +#if (RELAYFS_CHANNEL_VERSION >= 7) + _stp_relay_data.rchan = relay_open("trace", dir, utts->buf_size, + utts->buf_nr, + &__stp_relay_callbacks, NULL); #else - return 0; + _stp_relay_data.rchan = relay_open("trace", dir, utts->buf_size, + utts->buf_nr, + &__stp_relay_callbacks); #endif -} - - + if (!_stp_relay_data.rchan) + goto err; -static int -_stp_relay_subbuf_start_callback(struct rchan_buf *buf, void *subbuf, - void *prev_subbuf, size_t prev_padding) -{ - if (_stp_relay.overwrite_flag || !relay_buf_full(buf)) - return 1; + _stp_relay_data.transport_state = STP_TRANSPORT_INITIALIZED; - return 0; + utts->err = 0; + return utt; +err: + if (_stp_relay_data.dropped_file) + debugfs_remove(_stp_relay_data.dropped_file); + if (_stp_relay_data.rchan) + relay_close(_stp_relay_data.rchan); + if (dir) + __stp_relay_remove_tree(); + utts->err = ret; + return NULL; } -static struct dentry * -_stp_relay_create_buf_file_callback(const char *filename, - struct dentry *parent, - int mode, - struct rchan_buf *buf, - int *is_global) +static int utt_trace_startstop(struct _stp_relay_data_type *utt, int start) { - struct dentry *file; + int ret; - if (is_global) { -#ifdef STP_BULKMODE - *is_global = 0; -#else - *is_global = 1; -#endif + /* + * For starting a trace, we can transition from a setup or stopped + * trace. For stopping a trace, the state must be running + */ + ret = -EINVAL; + if (start) { + if (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED || + _stp_relay_data.transport_state == STP_TRANSPORT_STOPPED) { + __stp_relay_timer_init(); + smp_mb(); + _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; + ret = 0; + } + } else { + if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) { + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + del_timer_sync(&_stp_relay_data.timer); + relay_flush(_stp_relay_data.rchan); + ret = 0; + } } - file = debugfs_create_file(filename, mode, parent, buf, - &relay_file_operations); - if (file) { - file->d_inode->i_uid = _stp_uid; - file->d_inode->i_gid = _stp_gid; - } - return file; + return ret; } +#endif -static int -_stp_relay_remove_buf_file_callback(struct dentry *dentry) +static void _stp_transport_data_fs_close(void) { - debugfs_remove(dentry); - return 0; + if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) + del_timer_sync(&_stp_relay_data.timer); + + if (_stp_relay_data.dropped_file) + debugfs_remove(_stp_relay_data.dropped_file); + if (_stp_relay_data.rchan) { + relay_flush(_stp_relay_data.rchan); + relay_close(_stp_relay_data.rchan); + } + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; } -static struct rchan_callbacks _stp_relay_callbacks = { - .subbuf_start = _stp_relay_subbuf_start_callback, - .create_buf_file = _stp_relay_create_buf_file_callback, - .remove_buf_file = _stp_relay_remove_buf_file_callback, -}; - static int _stp_transport_data_fs_init(void) { int rc; u64 npages; struct sysinfo si; - _stp_relay.overwrite_flag = 0; + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + _stp_relay_data.overwrite_flag = 0; + atomic_set(&_stp_relay_data.dropped, 0); + _stp_relay_data.dropped_file = NULL; + _stp_relay_data.rchan = NULL; + + /* Create "dropped" file. */ + _stp_relay_data.dropped_file + = debugfs_create_file("dropped", 0444, _stp_get_module_dir(), + NULL, &__stp_relay_dropped_fops); + if (!_stp_relay_data.dropped_file) { + rc = -EIO; + goto err; + } + /* Create "trace" file. */ npages = _stp_subbuf_size * _stp_nsubbufs; #ifdef STP_BULKMODE npages *= num_possible_cpus(); @@ -518,33 +442,71 @@ static int _stp_transport_data_fs_init(void) "log buffer size exceeds free memory(%luMB)\n", MB(si.freeram)); } - #if (RELAYFS_CHANNEL_VERSION >= 7) - _stp_relay.rchan = relay_open("trace", _stp_get_module_dir(), - _stp_subbuf_size, _stp_nsubbufs, - &_stp_relay_callbacks, NULL); + _stp_relay_data.rchan = relay_open("trace", _stp_get_module_dir(), + _stp_subbuf_size, _stp_nsubbufs, + &__stp_relay_callbacks, NULL); #else /* (RELAYFS_CHANNEL_VERSION < 7) */ - _stp_relay.rchan = relay_open("trace", _stp_get_module_dir(), - _stp_subbuf_size, _stp_nsubbufs, - &_stp_relay_callbacks); + _stp_relay_data.rchan = relay_open("trace", _stp_get_module_dir(), + _stp_subbuf_size, _stp_nsubbufs, + &__stp_relay_callbacks); #endif /* (RELAYFS_CHANNEL_VERSION < 7) */ - - if (!_stp_relay.rchan) { + if (!_stp_relay_data.rchan) { rc = -ENOENT; goto err; } dbug_trans(1, "returning 0...\n"); + _stp_relay_data.transport_state = STP_TRANSPORT_INITIALIZED; + + /* We're initialized. Now start the timer. */ + __stp_relay_timer_init(); + _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; + return 0; err: - if (_stp_relay.rchan) - relay_close(_stp_relay.rchan); + _stp_transport_data_fs_close(); return rc; } -static void _stp_transport_data_fs_close(void) + +/** + * utt_reserve - reserve slot in channel buffer + * @utt: utt channel + * @length: number of bytes to reserve + * + * Returns pointer to reserved slot, NULL if full. + * + * This function is utt_switch_subbuf version of relay_reserve. + */ +static size_t +_stp_data_write_reserve(size_t size_request, void **entry) +{ + struct rchan_buf *buf; + + if (entry == NULL) + return -EINVAL; + + buf = _stp_relay_data.rchan->buf[smp_processor_id()]; + if (unlikely(buf->offset + size_request > buf->chan->subbuf_size)) { + size_request = __stp_relay_switch_subbuf(buf, size_request); + if (!size_request) + return 0; + } + *entry = (char*)buf->data + buf->offset; + buf->offset += size_request; + + return size_request; +} + +static unsigned char *_stp_data_entry_data(void *entry) { - if (_stp_relay.rchan) - relay_close(_stp_relay.rchan); + /* Nothing to do here. */ + return entry; } +static int _stp_data_write_commit(void *entry) +{ + /* Nothing to do here. */ + return 0; +} -- cgit From 42b8c995e8bac5a36be60870fca7f9ff1af2c2ab Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 8 May 2009 15:21:27 -0500 Subject: Cleaned up runtime/transport/relay_v2.c. * runtime/transport/relay_v2.c: Cleanup. --- runtime/transport/relay_v2.c | 196 ++++--------------------------------------- 1 file changed, 15 insertions(+), 181 deletions(-) diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index ea4d9241..9bcb6ee3 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -1,11 +1,14 @@ /* -*- linux-c -*- * - * This is a modified version of the proposed utt interface. If that - * interface makes it into the kernel, this file can go away. + * This transport version uses relayfs on top of a debugfs file. This + * code started as a proposed relayfs interface called 'utt'. It has + * been modified and simplified for systemtap. * - * Copyright (C) 2006 Jens Axboe + * Changes Copyright (C) 2009 Red Hat Inc. * - * Moved to utt.c by Tom Zanussi, 2006 + * Original utt code by: + * Copyright (C) 2006 Jens Axboe + * Moved to utt.c by Tom Zanussi, 2006 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -44,10 +47,8 @@ enum _stp_transport_state { struct _stp_relay_data_type { enum _stp_transport_state transport_state; struct rchan *rchan; - struct dentry *dir; /* systemtap/module_name */ struct dentry *dropped_file; atomic_t dropped; - struct dentry *utt_tree_root; /* systemtap */ atomic_t wakeup; struct timer_list timer; int overwrite_flag; @@ -151,67 +152,6 @@ static void stp_relay_set_overwrite(int overwrite) _stp_relay_data.overwrite_flag = overwrite; } -static void __stp_relay_remove_root(void) -{ - if (_stp_relay_data.utt_tree_root) { - if (!_stp_lock_transport_dir()) { - errk("Unable to lock transport directory.\n"); - return; - } - if (simple_empty(_stp_relay_data.utt_tree_root)) - debugfs_remove(_stp_relay_data.utt_tree_root); - _stp_unlock_transport_dir(); - _stp_relay_data.utt_tree_root = NULL; - } -} - -static void __stp_relay_remove_tree(void) -{ - if (_stp_relay_data.dir == NULL) - return; - debugfs_remove(_stp_relay_data.dir); - __stp_relay_remove_root(); -} - -static struct dentry *__stp_relay_create_tree(const char *root, - const char *name) -{ - struct dentry *dir = NULL; - - if (root == NULL || name == NULL) - return NULL; - - if (!_stp_relay_data.utt_tree_root) { - _stp_relay_data.utt_tree_root = _stp_get_root_dir(); - if (!_stp_relay_data.utt_tree_root) - goto err; - } - - dir = debugfs_create_dir(name, _stp_relay_data.utt_tree_root); - if (!dir) - __stp_relay_remove_root(); -err: - return dir; -} - -static void __stp_relay_cleanup(void) -{ - if (_stp_relay_data.rchan) - relay_close(_stp_relay_data.rchan); - if (_stp_relay_data.dropped_file) - debugfs_remove(_stp_relay_data.dropped_file); - __stp_relay_remove_tree(); -} - -static int _stp_relay_remove(void) -{ - if (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED || - _stp_relay_data.transport_state == STP_TRANSPORT_STOPPED) - __stp_relay_cleanup(); - - return 0; -} - static int __stp_relay_dropped_open(struct inode *inode, struct file *filp) { return 0; @@ -277,115 +217,6 @@ static struct rchan_callbacks __stp_relay_callbacks = { .remove_buf_file = __stp_relay_remove_buf_file_callback, }; -#if 0 -/* - * Setup everything required to start tracing - */ -static struct _stp_relay_data_type *utt_trace_setup(struct utt_trace_setup *utts) -{ - struct dentry *dir = NULL; - int ret = -EINVAL; - u64 npages; - struct sysinfo si; - - _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; - _stp_relay_data.overwrite_flag = 0; - - if (!utts->buf_size || !utts->buf_nr) - goto err; - - ret = -ENOENT; - dir = __stp_relay_create_tree(utts->root, utts->name); - if (!dir) - goto err; - _stp_relay_data.dir = dir; - atomic_set(&_stp_relay_data.dropped, 0); - - ret = -EIO; - _stp_relay_data.dropped_file = debugfs_create_file("dropped", 0444, - dir, NULL, - &__stp_relay_dropped_fops); - if (!_stp_relay_data.dropped_file) - goto err; - - npages = utts->buf_size * utts->buf_nr; -#ifndef STP_BULKMODE - npages *= num_possible_cpus(); -#endif - npages >>= PAGE_SHIFT; - si_meminfo(&si); -#define MB(i) (unsigned long)((i) >> (20 - PAGE_SHIFT)) - if (npages > (si.freeram + si.bufferram)) { - errk("Not enough free+buffered memory(%luMB) for log buffer(%luMB)\n", - MB(si.freeram + si.bufferram), - MB(npages)); - ret = -ENOMEM; - goto err; - } else if (npages > si.freeram) { - /* exceeds freeram, but below freeram+bufferram */ - printk(KERN_WARNING - "log buffer size exceeds free memory(%luMB)\n", - MB(si.freeram)); - } - -#if (RELAYFS_CHANNEL_VERSION >= 7) - _stp_relay_data.rchan = relay_open("trace", dir, utts->buf_size, - utts->buf_nr, - &__stp_relay_callbacks, NULL); -#else - _stp_relay_data.rchan = relay_open("trace", dir, utts->buf_size, - utts->buf_nr, - &__stp_relay_callbacks); -#endif - - if (!_stp_relay_data.rchan) - goto err; - - _stp_relay_data.transport_state = STP_TRANSPORT_INITIALIZED; - - utts->err = 0; - return utt; -err: - if (_stp_relay_data.dropped_file) - debugfs_remove(_stp_relay_data.dropped_file); - if (_stp_relay_data.rchan) - relay_close(_stp_relay_data.rchan); - if (dir) - __stp_relay_remove_tree(); - utts->err = ret; - return NULL; -} - -static int utt_trace_startstop(struct _stp_relay_data_type *utt, int start) -{ - int ret; - - /* - * For starting a trace, we can transition from a setup or stopped - * trace. For stopping a trace, the state must be running - */ - ret = -EINVAL; - if (start) { - if (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED || - _stp_relay_data.transport_state == STP_TRANSPORT_STOPPED) { - __stp_relay_timer_init(); - smp_mb(); - _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; - ret = 0; - } - } else { - if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) { - _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; - del_timer_sync(&_stp_relay_data.timer); - relay_flush(_stp_relay_data.rchan); - ret = 0; - } - } - - return ret; -} -#endif - static void _stp_transport_data_fs_close(void) { if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) @@ -471,13 +302,16 @@ err: /** - * utt_reserve - reserve slot in channel buffer - * @utt: utt channel - * @length: number of bytes to reserve + * _stp_data_write_reserve - try to reserve size_request bytes + * @size_request: number of bytes to attempt to reserve + * @entry: entry is returned here * - * Returns pointer to reserved slot, NULL if full. + * Returns number of bytes reserved, 0 if full. On return, entry + * will point to allocated opaque pointer. Use + * _stp_data_entry_data() to get pointer to copy data into. * - * This function is utt_switch_subbuf version of relay_reserve. + * (For this code's purposes, entry is filled in with the actual + * data pointer, but the caller doesn't know that.) */ static size_t _stp_data_write_reserve(size_t size_request, void **entry) -- cgit From 945563a795f312551157b69542ed1bc3323203c7 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 8 May 2009 15:28:56 -0500 Subject: Sets uid/gid on "dropped" file. * runtime/transport/relay_v2.c (_stp_transport_data_fs_init): Sets uid/gid on "dropped" file. --- runtime/transport/relay_v2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index 9bcb6ee3..c0a772ed 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -251,6 +251,8 @@ static int _stp_transport_data_fs_init(void) rc = -EIO; goto err; } + _stp_relay_data.dropped_file->d_inode->i_uid = _stp_uid; + _stp_relay_data.dropped_file->d_inode->i_gid = _stp_gid; /* Create "trace" file. */ npages = _stp_subbuf_size * _stp_nsubbufs; -- cgit From dd9a3bcbef65bde65491d959e9458bc641924811 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 12 May 2009 13:38:48 -0500 Subject: Start at supporting the original transport (STP_TRANSPORT_VERSION=1). * runtime/print.c: Only use print_new.c. * runtime/print_new.c (stp_print_flush): Add STP_TRANSPORT_VERSION 1 support. * runtime/transport/transport.c: Removed inclusion of procfs.c. * runtime/transport/procfs.c (_stp_proc_read): Adapt to new interface. (_stp_proc_write): Ditto. * runtime/transport/relayfs.c: Ditto. --- runtime/print.c | 6 -- runtime/print_new.c | 9 ++ runtime/transport/procfs.c | 11 ++- runtime/transport/relayfs.c | 187 +++++++++++++++++++----------------------- runtime/transport/transport.c | 1 - 5 files changed, 100 insertions(+), 114 deletions(-) diff --git a/runtime/print.c b/runtime/print.c index 2e205f10..c1fff306 100644 --- a/runtime/print.c +++ b/runtime/print.c @@ -87,14 +87,8 @@ static void _stp_print_cleanup (void) #endif #if !defined(RELAY_GUEST) -/* The relayfs API changed between 2.6.15 and 2.6.16. */ -/* Use the appropriate print flush function. */ -#if STP_TRANSPORT_VERSION == 1 -#include "print_old.c" -#else #include "print_new.c" -#endif #if defined(RELAY_HOST) EXPORT_SYMBOL_GPL(EXPORT_FN(stp_print_flush)); #endif diff --git a/runtime/print_new.c b/runtime/print_new.c index b6187978..2d5a6e10 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -92,7 +92,15 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) } } #endif /* !NO_PERCPU_HEADERS */ + #else /* !STP_BULKMODE */ + +#if STP_TRANSPORT_VERSION == 1 + + if (unlikely(_stp_ctl_write(STP_REALTIME_DATA, pb->buf, len) <= 0)) + atomic_inc (&_stp_transport_failures); + +#else /* STP_TRANSPORT_VERSION != 1 */ { unsigned long flags; char *bufp = pb->buf; @@ -117,5 +125,6 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) } spin_unlock_irqrestore(&_stp_print_lock, flags); } +#endif /* STP_TRANSPORT_VERSION != 1 */ #endif /* !STP_BULKMODE */ } diff --git a/runtime/transport/procfs.c b/runtime/transport/procfs.c index 6afbdea1..9e05cc14 100644 --- a/runtime/transport/procfs.c +++ b/runtime/transport/procfs.c @@ -14,7 +14,6 @@ #define STP_DEFAULT_BUFFERS 256 #ifdef STP_BULKMODE -extern int _stp_relay_flushing; /* handle the per-cpu subbuf info read for relayfs */ static ssize_t _stp_proc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -23,13 +22,13 @@ static ssize_t _stp_proc_read(struct file *file, char __user *buf, size_t count, int cpu = *(int *)(PDE(file->f_dentry->d_inode)->data); - if (!_stp_utt->rchan) + if (!_stp_relay_data.rchan) return -EINVAL; out.cpu = cpu; - out.produced = atomic_read(&_stp_utt->rchan->buf[cpu]->subbufs_produced); - out.consumed = atomic_read(&_stp_utt->rchan->buf[cpu]->subbufs_consumed); - out.flushing = _stp_relay_flushing; + out.produced = atomic_read(&_stp_relay_data.rchan->buf[cpu]->subbufs_produced); + out.consumed = atomic_read(&_stp_relay_data.rchan->buf[cpu]->subbufs_consumed); + out.flushing = _stp_relay_data.flushing; num = sizeof(out); if (copy_to_user(buf, &out, num)) @@ -46,7 +45,7 @@ static ssize_t _stp_proc_write(struct file *file, const char __user *buf, size_t if (copy_from_user(&info, buf, count)) return -EFAULT; - relay_subbufs_consumed(_stp_utt->rchan, cpu, info.consumed); + relay_subbufs_consumed(_stp_relay_data.rchan, cpu, info.consumed); return count; } diff --git a/runtime/transport/relayfs.c b/runtime/transport/relayfs.c index 42be4283..dac6db1d 100644 --- a/runtime/transport/relayfs.c +++ b/runtime/transport/relayfs.c @@ -22,17 +22,33 @@ #include #include #include -#include "utt.h" -static int _stp_relay_flushing = 0; +enum _stp_transport_state { + STP_TRANSPORT_STOPPED, + STP_TRANSPORT_INITIALIZED, + STP_TRANSPORT_RUNNING, +}; + +struct _stp_relay_data_type { + enum _stp_transport_state transport_state; + struct rchan *rchan; + int flushing; +}; +struct _stp_relay_data_type _stp_relay_data; + +/* We need to include procfs.c here so that it can see the + * _stp_relay_data_type definition. */ +#include "procfs.c" /** - * _stp_subbuf_start - subbuf_start() relayfs callback implementation + * __stp_relay_subbuf_start_callback - subbuf_start() relayfs + * callback implementation */ -static int _stp_subbuf_start(struct rchan_buf *buf, - void *subbuf, - unsigned prev_subbuf_idx, - void *prev_subbuf) +static int +__stp_relay_subbuf_start_callback(struct rchan_buf *buf, + void *subbuf, + unsigned prev_subbuf_idx, + void *prev_subbuf) { unsigned padding = buf->padding[prev_subbuf_idx]; if (prev_subbuf) @@ -42,11 +58,12 @@ static int _stp_subbuf_start(struct rchan_buf *buf, } /** - * _stp_buf_full - buf_full() relayfs callback implementation + * __stp_relay_buf_full_callback - buf_full() relayfs callback + * implementation */ -static void _stp_buf_full(struct rchan_buf *buf, - unsigned subbuf_idx, - void *subbuf) +static void __stp_relay_buf_full_callback(struct rchan_buf *buf, + unsigned subbuf_idx, + void *subbuf) { unsigned padding = buf->padding[subbuf_idx]; *((unsigned *)subbuf) = padding; @@ -54,126 +71,94 @@ static void _stp_buf_full(struct rchan_buf *buf, static struct rchan_callbacks stp_rchan_callbacks = { - .subbuf_start = _stp_subbuf_start, - .buf_full = _stp_buf_full, + .subbuf_start = __stp_relay_subbuf_start_callback, + .buf_full = __stp_relay_buf_full_callback, }; - -static void _stp_remove_relay_dir(struct dentry *dir) -{ - if (dir) - relayfs_remove_dir(dir); -} - -static void _stp_remove_relay_root(struct dentry *root) +static void _stp_transport_data_fs_close(void) { - if (root) { - if (!_stp_lock_transport_dir()) { - errk("Unable to lock transport directory.\n"); - return; - } - _stp_remove_relay_dir(root); - _stp_unlock_transport_dir(); + if (_stp_relay_data.rchan) { + _stp_relay_data.flushing = 1; + relay_flush(_stp_relay_data.rchan); + relay_close(_stp_relay_data.rchan); } + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; } -static struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts) +static int _stp_transport_data_fs_init(void) { - struct utt_trace *utt; + int rc = 0; int i; - utt = _stp_kzalloc(sizeof(*utt)); - if (!utt) - return NULL; - - utt->utt_tree_root = _stp_get_root_dir(); - if (!utt->utt_tree_root) - goto err; - - utt->dir = relayfs_create_dir(utts->name, utt->utt_tree_root); - if (!utt->dir) - goto err; - - dbug_trans(1, "relay_open %d %d\n", utts->buf_size, utts->buf_nr); + dbug_trans(1, "relay_open %d %d\n", _stp_subbuf_size, _stp_nsubbufs); + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + _stp_relay_data.flushing = 0; - utt->rchan = relay_open("trace", utt->dir, utts->buf_size, - utts->buf_nr, 0, &stp_rchan_callbacks); - if (!utt->rchan) + /* Create "trace" file. */ + _stp_relay_data.rchan = relay_open("trace", _stp_get_module_dir(), + _stp_subbuf_size, _stp_nsubbufs, + 0, &stp_rchan_callbacks); + if (!_stp_relay_data.rchan) { + rc = -ENOENT; goto err; + } /* now set ownership */ for_each_online_cpu(i) { - utt->rchan->buf[i]->dentry->d_inode->i_uid = _stp_uid; - utt->rchan->buf[i]->dentry->d_inode->i_gid = _stp_gid; + _stp_relay_data.rchan->buf[i]->dentry->d_inode->i_uid + = _stp_uid; + _stp_relay_data.rchan->buf[i]->dentry->d_inode->i_gid + = _stp_gid; } - utt->rchan->private_data = utt; - utt->trace_state = Utt_trace_setup; - utts->err = 0; - return utt; + /* We're off and running. */ + smp_mb(); + _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; + return rc; err: errk("couldn't create relay channel.\n"); - if (utt->dir) - _stp_remove_relay_dir(utt->dir); - if (utt->utt_tree_root) - _stp_remove_relay_root(utt->utt_tree_root); - _stp_kfree(utt); - return NULL; + _stp_transport_data_fs_close(); + return rc; } -static void utt_set_overwrite(int overwrite) +static void stp_relay_set_overwrite(int overwrite) { - if (_stp_utt) - _stp_utt->rchan->overwrite = overwrite; + _stp_relay_data.rchan->overwrite = overwrite; } -static int utt_trace_startstop(struct utt_trace *utt, int start, - unsigned int *trace_seq) +/** + * _stp_data_write_reserve - try to reserve size_request bytes + * @size_request: number of bytes to attempt to reserve + * @entry: entry is returned here + * + * Returns number of bytes reserved, 0 if full. On return, entry + * will point to allocated opaque pointer. Use + * _stp_data_entry_data() to get pointer to copy data into. + * + * (For this code's purposes, entry is filled in with the actual + * data pointer, but the caller doesn't know that.) + */ +static size_t +_stp_data_write_reserve(size_t size_request, void **entry) { - int ret; + if (entry == NULL) + return -EINVAL; - if (!utt) + *entry = relay_reserve(_stp_relay_data.rchan, size_request); + if (*entry == NULL) return 0; - - /* - * For starting a trace, we can transition from a setup or stopped - * trace. For stopping a trace, the state must be running - */ - ret = -EINVAL; - if (start) { - if (utt->trace_state == Utt_trace_setup || - utt->trace_state == Utt_trace_stopped) { - if (trace_seq) - (*trace_seq)++; - smp_mb(); - utt->trace_state = Utt_trace_running; - ret = 0; - } - } else { - if (utt->trace_state == Utt_trace_running) { - utt->trace_state = Utt_trace_stopped; - _stp_relay_flushing = 1; - relay_flush(utt->rchan); - ret = 0; - } - } - - return ret; + return size_request; } +static unsigned char *_stp_data_entry_data(void *entry) +{ + /* Nothing to do here. */ + return entry; +} -static int utt_trace_remove(struct utt_trace *utt) +static int _stp_data_write_commit(void *entry) { - dbug_trans(1, "removing relayfs files. %d\n", utt->trace_state); - if (utt && (utt->trace_state == Utt_trace_setup || utt->trace_state == Utt_trace_stopped)) { - if (utt->rchan) - relay_close(utt->rchan); - if (utt->dir) - _stp_remove_relay_dir(utt->dir); - if (utt->utt_tree_root) - _stp_remove_relay_root(utt->utt_tree_root); - _stp_kfree(utt); - } + /* Nothing to do here. */ return 0; } diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 5a499e8d..3d0453bf 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -44,7 +44,6 @@ static int _stp_probes_started = 0; #include "control.h" #if STP_TRANSPORT_VERSION == 1 #include "relayfs.c" -#include "procfs.c" #elif STP_TRANSPORT_VERSION == 2 #include "relay_v2.c" #include "debugfs.c" -- 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/debugfs.c | 7 + runtime/transport/relay_v2.c | 11 +- runtime/transport/ring_buffer.c | 7 + runtime/transport/transport.c | 18 ++ runtime/transport/utt.c | 404 ---------------------------------------- runtime/transport/utt.h | 83 --------- runtime/vsprintf.c | 2 + 7 files changed, 44 insertions(+), 488 deletions(-) delete mode 100644 runtime/transport/utt.c delete mode 100644 runtime/transport/utt.h diff --git a/runtime/transport/debugfs.c b/runtime/transport/debugfs.c index 7a08982a..6bbef53b 100644 --- a/runtime/transport/debugfs.c +++ b/runtime/transport/debugfs.c @@ -36,6 +36,13 @@ static int _stp_register_ctl_channel_fs(void) errk("Error creating systemtap debugfs entries.\n"); return -1; } + else if (IS_ERR(_stp_cmd_file)) { + _stp_cmd_file = NULL; + errk("Error creating systemtap debugfs entries: %ld\n", + -PTR_ERR(_stp_cmd_file)); + return -1; + } + _stp_cmd_file->d_inode->i_uid = _stp_uid; _stp_cmd_file->d_inode->i_gid = _stp_gid; diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index c0a772ed..0c8d0955 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -204,7 +204,10 @@ __stp_relay_create_buf_file_callback(const char *filename, { struct dentry *file = debugfs_create_file(filename, mode, parent, buf, &relay_file_operations); - if (file) { + if (IS_ERR(file)) { + file = NULL; + } + else if (file) { file->d_inode->i_uid = _stp_uid; file->d_inode->i_gid = _stp_gid; } @@ -251,6 +254,12 @@ static int _stp_transport_data_fs_init(void) rc = -EIO; goto err; } + else if (IS_ERR(_stp_relay_data.dropped_file)) { + rc = PTR_ERR(_stp_relay_data.dropped_file); + _stp_relay_data.dropped_file = NULL; + goto err; + } + _stp_relay_data.dropped_file->d_inode->i_uid = _stp_uid; _stp_relay_data.dropped_file->d_inode->i_gid = _stp_gid; 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; diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 792ea815..ab0806f2 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -453,6 +453,12 @@ static struct dentry *_stp_get_root_dir(void) errk("Could not create or find transport directory.\n"); } } + else if (IS_ERR(__stp_root_dir)) { + __stp_root_dir = NULL; + errk("Could not create root directory \"%s\", error %ld\n", name, + -PTR_ERR(__stp_root_dir)); + } + _stp_unlock_transport_dir(); return __stp_root_dir; } @@ -490,8 +496,20 @@ static int _stp_transport_fs_init(const char *module_name) if (root_dir == NULL) return -1; +#if STP_TRANSPORT_VERSION == 1 + __stp_module_dir = relayfs_create_dir(module_name, root_dir); +#else __stp_module_dir = debugfs_create_dir(module_name, root_dir); +#endif if (!__stp_module_dir) { + errk("Could not create module directory \"%s\"\n", + module_name); + _stp_remove_root_dir(); + return -1; + } + else if (IS_ERR(__stp_module_dir)) { + errk("Could not create module directory \"%s\", error %ld\n", + module_name, -PTR_ERR(__stp_module_dir)); _stp_remove_root_dir(); return -1; } diff --git a/runtime/transport/utt.c b/runtime/transport/utt.c deleted file mode 100644 index 2dd303a5..00000000 --- a/runtime/transport/utt.c +++ /dev/null @@ -1,404 +0,0 @@ -/* -*- linux-c -*- - * - * This is a modified version of the proposed utt interface. If that - * interface makes it into the kernel, this file can go away. - * - * Copyright (C) 2006 Jens Axboe - * - * Moved to utt.c by Tom Zanussi, 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#include -#include -#include -#include -#include -#include -#include "utt.h" - -static int utt_overwrite_flag = 0; - -/* - * utt_switch_subbuf - switch to a new sub-buffer - * - * Most of this function is deadcopy of relay_switch_subbuf. - */ -static size_t utt_switch_subbuf(struct utt_trace *utt, struct rchan_buf *buf, - size_t length) -{ - char *old, *new; - size_t old_subbuf, new_subbuf; - - if (unlikely(buf == NULL)) - return 0; - - if (unlikely(length > buf->chan->subbuf_size)) - goto toobig; - - if (buf->offset != buf->chan->subbuf_size + 1) { - buf->prev_padding = buf->chan->subbuf_size - buf->offset; - old_subbuf = buf->subbufs_produced % buf->chan->n_subbufs; - buf->padding[old_subbuf] = buf->prev_padding; - buf->subbufs_produced++; - buf->dentry->d_inode->i_size += buf->chan->subbuf_size - - buf->padding[old_subbuf]; - smp_mb(); - if (waitqueue_active(&buf->read_wait)) - /* - * Calling wake_up_interruptible() and __mod_timer() - * from here will deadlock if we happen to be logging - * from the scheduler and timer (trying to re-grab - * rq->lock/timer->base->lock), so just set a flag. - */ - atomic_set(&utt->wakeup, 1); - } - - old = buf->data; - new_subbuf = buf->subbufs_produced % buf->chan->n_subbufs; - new = (char*)buf->start + new_subbuf * buf->chan->subbuf_size; - buf->offset = 0; - if (!buf->chan->cb->subbuf_start(buf, new, old, buf->prev_padding)) { - buf->offset = buf->chan->subbuf_size + 1; - return 0; - } - buf->data = new; - buf->padding[new_subbuf] = 0; - - if (unlikely(length + buf->offset > buf->chan->subbuf_size)) - goto toobig; - - return length; - -toobig: - buf->chan->last_toobig = length; - return 0; -} - -static void __utt_wakeup_readers(struct rchan_buf *buf) -{ - if (buf && waitqueue_active(&buf->read_wait) && - buf->subbufs_produced != buf->subbufs_consumed) - wake_up_interruptible(&buf->read_wait); -} - -static void __utt_wakeup_timer(unsigned long val) -{ - struct utt_trace *utt = (struct utt_trace *)val; - int i; - - if (atomic_read(&utt->wakeup)) { - atomic_set(&utt->wakeup, 0); - if (utt->is_global) - __utt_wakeup_readers(utt->rchan->buf[0]); - else - for_each_possible_cpu(i) - __utt_wakeup_readers(utt->rchan->buf[i]); - } - - mod_timer(&utt->timer, jiffies + UTT_TIMER_INTERVAL); -} - -static void __utt_timer_init(struct utt_trace * utt) -{ - atomic_set(&utt->wakeup, 0); - init_timer(&utt->timer); - utt->timer.expires = jiffies + UTT_TIMER_INTERVAL; - utt->timer.function = __utt_wakeup_timer; - utt->timer.data = (unsigned long)utt; - add_timer(&utt->timer); -} - -static void utt_set_overwrite(int overwrite) -{ - utt_overwrite_flag = overwrite; -} - -static void utt_remove_root(struct utt_trace *utt) -{ - if (utt->utt_tree_root) { - if (!_stp_lock_transport_dir()) { - errk("Unable to lock transport directory.\n"); - return; - } - if (simple_empty(utt->utt_tree_root)) - debugfs_remove(utt->utt_tree_root); - _stp_unlock_transport_dir(); - utt->utt_tree_root = NULL; - } -} - -static void utt_remove_tree(struct utt_trace *utt) -{ - if (utt == NULL || utt->dir == NULL) - return; - debugfs_remove(utt->dir); - utt_remove_root(utt); -} - -static struct dentry *utt_create_tree(struct utt_trace *utt, const char *root, const char *name) -{ - struct dentry *dir = NULL; - - if (root == NULL || name == NULL) - return NULL; - - if (!utt->utt_tree_root) { - utt->utt_tree_root = _stp_get_root_dir(); - if (!utt->utt_tree_root) - goto err; - } - - dir = debugfs_create_dir(name, utt->utt_tree_root); - if (!dir) - utt_remove_root(utt); -err: - return dir; -} - -static void utt_trace_cleanup(struct utt_trace *utt) -{ - if (utt == NULL) - return; - if (utt->rchan) - relay_close(utt->rchan); - if (utt->dropped_file) - debugfs_remove(utt->dropped_file); - utt_remove_tree(utt); - _stp_kfree(utt); -} - -static int utt_trace_remove(struct utt_trace *utt) -{ - if (utt->trace_state == Utt_trace_setup || - utt->trace_state == Utt_trace_stopped) - utt_trace_cleanup(utt); - - return 0; -} - -static int utt_dropped_open(struct inode *inode, struct file *filp) -{ -#ifdef STAPCONF_INODE_PRIVATE - filp->private_data = inode->i_private; -#else - filp->private_data = inode->u.generic_ip; -#endif - return 0; -} - -static ssize_t utt_dropped_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct utt_trace *utt = filp->private_data; - char buf[16]; - - snprintf(buf, sizeof(buf), "%u\n", atomic_read(&utt->dropped)); - - return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); -} - -static struct file_operations utt_dropped_fops = { - .owner = THIS_MODULE, - .open = utt_dropped_open, - .read = utt_dropped_read, -}; - -/* - * Keep track of how many times we encountered a full subbuffer, to aid - * the user space app in telling how many lost events there were. - */ -static int utt_subbuf_start_callback(struct rchan_buf *buf, void *subbuf, - void *prev_subbuf, size_t prev_padding) -{ - struct utt_trace *utt; - - if (utt_overwrite_flag || !relay_buf_full(buf)) - return 1; - - utt = buf->chan->private_data; - atomic_inc(&utt->dropped); - return 0; -} - -static int utt_remove_buf_file_callback(struct dentry *dentry) -{ - debugfs_remove(dentry); - return 0; -} - -static struct dentry *utt_create_buf_file_callback(const char *filename, - struct dentry *parent, - int mode, - struct rchan_buf *buf, - int *is_global) -{ - struct dentry *file = debugfs_create_file(filename, mode, parent, buf, - &relay_file_operations); - if (file) { - file->d_inode->i_uid = _stp_uid; - file->d_inode->i_gid = _stp_gid; - } - return file; -} - -static struct dentry *utt_create_global_buf_file_callback(const char *filename, - struct dentry *parent, - int mode, - struct rchan_buf *buf, - int *is_global) -{ - struct dentry *file; - *is_global = 1; - file = debugfs_create_file(filename, mode, parent, buf, - &relay_file_operations); - if (file) { - file->d_inode->i_uid = _stp_uid; - file->d_inode->i_gid = _stp_gid; - } - return file; -} - -static struct rchan_callbacks utt_relay_callbacks = { - .subbuf_start = utt_subbuf_start_callback, - .create_buf_file = utt_create_buf_file_callback, - .remove_buf_file = utt_remove_buf_file_callback, -}; - -static struct rchan_callbacks utt_relay_callbacks_global = { - .subbuf_start = utt_subbuf_start_callback, - .create_buf_file = utt_create_global_buf_file_callback, - .remove_buf_file = utt_remove_buf_file_callback, -}; - -/* - * Setup everything required to start tracing - */ -static struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts) -{ - struct utt_trace *utt = NULL; - struct dentry *dir = NULL; - int ret = -EINVAL; - u64 npages; - struct sysinfo si; - - if (!utts->buf_size || !utts->buf_nr) - goto err; - - ret = -ENOMEM; - utt = _stp_kzalloc(sizeof(*utt)); - if (!utt) - goto err; - - ret = -ENOENT; - dir = utt_create_tree(utt, utts->root, utts->name); - if (!dir) - goto err; - utt->dir = dir; - atomic_set(&utt->dropped, 0); - - ret = -EIO; - utt->dropped_file = debugfs_create_file("dropped", 0444, dir, utt, &utt_dropped_fops); - if (!utt->dropped_file) - goto err; - - npages = utts->buf_size * utts->buf_nr; - if (!utts->is_global) - npages *= num_possible_cpus(); - npages >>= PAGE_SHIFT; - si_meminfo(&si); -#define MB(i) (unsigned long)((i) >> (20 - PAGE_SHIFT)) - if (npages > (si.freeram + si.bufferram)) { - errk("Not enough free+buffered memory(%luMB) for log buffer(%luMB)\n", - MB(si.freeram + si.bufferram), - MB(npages)); - ret = -ENOMEM; - goto err; - } else if (npages > si.freeram) { - /* exceeds freeram, but below freeram+bufferram */ - printk(KERN_WARNING - "log buffer size exceeds free memory(%luMB)\n", - MB(si.freeram)); - } - -#if (RELAYFS_CHANNEL_VERSION >= 7) - if (utts->is_global) - utt->rchan = relay_open("trace", dir, utts->buf_size, utts->buf_nr, - &utt_relay_callbacks_global, NULL); - else - utt->rchan = relay_open("trace", dir, utts->buf_size, utts->buf_nr, - &utt_relay_callbacks, NULL); -#else - if (utts->is_global) - utt->rchan = relay_open("trace", dir, utts->buf_size, utts->buf_nr, &utt_relay_callbacks_global); - else - utt->rchan = relay_open("trace", dir, utts->buf_size, utts->buf_nr, &utt_relay_callbacks); -#endif - - if (!utt->rchan) - goto err; - utt->rchan->private_data = utt; - - utt->is_global = utts->is_global; - - utt->trace_state = Utt_trace_setup; - - utts->err = 0; - return utt; -err: - if (utt) { - if (utt->dropped_file) - debugfs_remove(utt->dropped_file); - if (utt->rchan) - relay_close(utt->rchan); - _stp_kfree(utt); - } - if (dir) - utt_remove_tree(utt); - utts->err = ret; - return NULL; -} - -static int utt_trace_startstop(struct utt_trace *utt, int start, - unsigned int *trace_seq) -{ - int ret; - - /* - * For starting a trace, we can transition from a setup or stopped - * trace. For stopping a trace, the state must be running - */ - ret = -EINVAL; - if (start) { - if (utt->trace_state == Utt_trace_setup || - utt->trace_state == Utt_trace_stopped) { - if (trace_seq) - (*trace_seq)++; - __utt_timer_init(utt); - smp_mb(); - utt->trace_state = Utt_trace_running; - ret = 0; - } - } else { - if (utt->trace_state == Utt_trace_running) { - utt->trace_state = Utt_trace_stopped; - del_timer_sync(&utt->timer); - relay_flush(utt->rchan); - ret = 0; - } - } - - return ret; -} diff --git a/runtime/transport/utt.h b/runtime/transport/utt.h deleted file mode 100644 index 2a479d70..00000000 --- a/runtime/transport/utt.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef UTT_H -#define UTT_H - -enum { - Utt_trace_setup = 1, - Utt_trace_running, - Utt_trace_stopped, -}; - -struct utt_trace { - int trace_state; -// struct rchan *rchan; - struct dentry *dir; /* systemtap/module_name */ - struct dentry *dropped_file; - atomic_t dropped; - struct dentry *utt_tree_root; /* systemtap */ - void *private_data; - atomic_t wakeup; - struct timer_list timer; - int is_global; -}; - -#define UTT_TRACE_ROOT_NAME_SIZE 64 /* Largest string for a root dir identifier */ -#define UTT_TRACE_NAME_SIZE 64 /* Largest string for a trace identifier */ - -#ifndef UTT_TIMER_INTERVAL -#define UTT_TIMER_INTERVAL ((HZ + 99) / 100) /* Wakeup timer interval in jiffies (default 10 ms)*/ -#endif - -/* - * User setup structure - */ -struct utt_trace_setup { - char root[UTT_TRACE_ROOT_NAME_SIZE]; /* input */ - char name[UTT_TRACE_NAME_SIZE]; /* input */ - u32 buf_size; /* input */ - u32 buf_nr; /* input */ - int is_global; /* input */ - int err; /* output */ -}; - - -static struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts); - -static int utt_trace_startstop(struct utt_trace *utt, int start, - unsigned int *trace_seq); -static void utt_trace_cleanup(struct utt_trace *utt); -static int utt_trace_remove(struct utt_trace *utt); - -#if STP_TRANSPORT_VERSION == 2 -static size_t utt_switch_subbuf(struct utt_trace *utt, struct rchan_buf *buf, - size_t length); -/** - * utt_reserve - reserve slot in channel buffer - * @utt: utt channel - * @length: number of bytes to reserve - * - * Returns pointer to reserved slot, NULL if full. - * - * This function is utt_switch_subbuf version of relay_reserve. - */ -static inline void *utt_reserve(struct utt_trace *utt, size_t length) -{ -#if 0 - void *reserved; - struct rchan_buf *buf = utt->rchan->buf[smp_processor_id()]; - - if (unlikely(buf->offset + length > buf->chan->subbuf_size)) { - length = utt_switch_subbuf(utt, buf, length); - if (!length) - return NULL; - } - reserved = (char*)buf->data + buf->offset; - buf->offset += length; - - return reserved; -#else - return NULL; -#endif -} -#endif - -#endif diff --git a/runtime/vsprintf.c b/runtime/vsprintf.c index 23810e75..674946b9 100644 --- a/runtime/vsprintf.c +++ b/runtime/vsprintf.c @@ -12,6 +12,8 @@ #ifndef _VSPRINTF_C_ #define _VSPRINTF_C_ +#include "transport/transport.h" + //forward declaration for _stp_vsnprintf static void * _stp_reserve_bytes (int); -- cgit From a655ff03c59722c229a40909d0de9e3dfe63483e Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 26 May 2009 14:08:57 -0500 Subject: Cleanup and better original transport support. * runtime/print.h: Moved _stp_reserve_bytes() prototype here. * runtime/vsprintf.c (_stp_vsnprintf): Includes print.h to get _stp_reserve_bytes() prototype. * runtime/transport/transport.c (_stp_remove_root_dir): Better cleanup for STP_TRANSPORT_VERSION == 1. (_stp_transport_fs_close): Ditto. --- runtime/print.h | 1 + runtime/transport/transport.c | 11 ++++++++++- runtime/vsprintf.c | 4 +--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/runtime/print.h b/runtime/print.h index d5c588a3..c2731a2f 100644 --- a/runtime/print.h +++ b/runtime/print.h @@ -12,5 +12,6 @@ static int _stp_print_init(void); static void _stp_print_cleanup(void); +static void *_stp_reserve_bytes(int numbytes); #endif /* _STP_PRINT_H_ */ diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index ab0806f2..8425536a 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -470,8 +470,13 @@ static void _stp_remove_root_dir(void) errk("Unable to lock transport directory.\n"); return; } - if (simple_empty(__stp_root_dir)) + if (simple_empty(__stp_root_dir)) { +#if STP_TRANSPORT_VERSION == 1 + relayfs_remove_dir(__stp_root_dir); +#else debugfs_remove(__stp_root_dir); +#endif + } _stp_unlock_transport_dir(); __stp_root_dir = NULL; } @@ -529,7 +534,11 @@ static void _stp_transport_fs_close(void) _stp_transport_data_fs_close(); if (__stp_module_dir) { +#if STP_TRANSPORT_VERSION == 1 + relayfs_remove_dir(__stp_module_dir); +#else debugfs_remove(__stp_module_dir); +#endif __stp_module_dir = NULL; } diff --git a/runtime/vsprintf.c b/runtime/vsprintf.c index 674946b9..5875d509 100644 --- a/runtime/vsprintf.c +++ b/runtime/vsprintf.c @@ -12,11 +12,9 @@ #ifndef _VSPRINTF_C_ #define _VSPRINTF_C_ +#include "print.h" #include "transport/transport.h" -//forward declaration for _stp_vsnprintf -static void * _stp_reserve_bytes (int); - static int skip_atoi(const char **s) { int i=0; -- 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/control.c | 18 ++++++++++++++++++ runtime/transport/relay_v2.c | 29 +++++++++++++++++++++-------- runtime/transport/relayfs.c | 26 ++++++++++++++++++++------ runtime/transport/ring_buffer.c | 10 ++++++++++ runtime/transport/transport.c | 13 ++++--------- runtime/transport/transport.h | 14 ++++++++++++++ 6 files changed, 87 insertions(+), 23 deletions(-) diff --git a/runtime/transport/control.c b/runtime/transport/control.c index a1624152..11338eb2 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -100,6 +100,24 @@ static void _stp_ctl_write_dbug(int type, void *data, int len) case STP_TRANSPORT: _dbug("sending STP_TRANSPORT\n"); break; + case STP_CONNECT: + _dbug("sending STP_CONNECT\n"); + break; + case STP_DISCONNECT: + _dbug("sending STP_DISCONNECT\n"); + break; + case STP_BULK: + _dbug("sending STP_BULK\n"); + break; + case STP_READY: + case STP_RELOCATION: + case STP_BUF_INFO: + case STP_SUBBUFS_CONSUMED: + _dbug("sending old message\n"); + break; + case STP_REALTIME_DATA: + _dbug("sending %d bytes of STP_REALTIME_DATA\n", len); + break; case STP_REQUEST_EXIT: _dbug("sending STP_REQUEST_EXIT\n"); break; diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index 0c8d0955..16b5afa1 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -220,18 +220,35 @@ static struct rchan_callbacks __stp_relay_callbacks = { .remove_buf_file = __stp_relay_remove_buf_file_callback, }; -static void _stp_transport_data_fs_close(void) +static void _stp_transport_data_fs_start(void) +{ + if (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED) { + /* We're initialized. Now start the timer. */ + __stp_relay_timer_init(); + _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; + } +} + +static void _stp_transport_data_fs_stop(void) { - if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) + if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) { del_timer_sync(&_stp_relay_data.timer); + dbug_trans(0, "flushing...\n"); + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + if (_stp_relay_data.rchan) + relay_flush(_stp_relay_data.rchan); + } +} +static void _stp_transport_data_fs_close(void) +{ + _stp_transport_data_fs_stop(); if (_stp_relay_data.dropped_file) debugfs_remove(_stp_relay_data.dropped_file); if (_stp_relay_data.rchan) { - relay_flush(_stp_relay_data.rchan); relay_close(_stp_relay_data.rchan); + _stp_relay_data.rchan = NULL; } - _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; } static int _stp_transport_data_fs_init(void) @@ -300,10 +317,6 @@ static int _stp_transport_data_fs_init(void) dbug_trans(1, "returning 0...\n"); _stp_relay_data.transport_state = STP_TRANSPORT_INITIALIZED; - /* We're initialized. Now start the timer. */ - __stp_relay_timer_init(); - _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; - return 0; err: diff --git a/runtime/transport/relayfs.c b/runtime/transport/relayfs.c index dac6db1d..191b932f 100644 --- a/runtime/transport/relayfs.c +++ b/runtime/transport/relayfs.c @@ -75,14 +75,29 @@ static struct rchan_callbacks stp_rchan_callbacks = .buf_full = __stp_relay_buf_full_callback, }; +static void _stp_transport_data_fs_start(void) +{ + 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) +{ + if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) { + _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; + _stp_relay_data.flushing = 1; + if (_stp_relay_data.rchan) + relay_flush(_stp_relay_data.rchan); + } +} + static void _stp_transport_data_fs_close(void) { + _stp_transport_data_fs_stop(); if (_stp_relay_data.rchan) { - _stp_relay_data.flushing = 1; - relay_flush(_stp_relay_data.rchan); relay_close(_stp_relay_data.rchan); + _stp_relay_data.rchan = NULL; } - _stp_relay_data.transport_state = STP_TRANSPORT_STOPPED; } static int _stp_transport_data_fs_init(void) @@ -111,9 +126,8 @@ static int _stp_transport_data_fs_init(void) = _stp_gid; } - /* We're off and running. */ - smp_mb(); - _stp_relay_data.transport_state = STP_TRANSPORT_RUNNING; + /* We're initialized. */ + _stp_relay_data.transport_state = STP_TRANSPORT_INITIALIZED; return rc; err: 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; diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 8425536a..84959f71 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -135,11 +135,8 @@ static void _stp_cleanup_and_exit(int send_exit) if (failures) _stp_warn("There were %d transport failures.\n", failures); - dbug_trans(1, "************** calling startstop 0 *************\n"); -#if 0 - if (_stp_utt) - utt_trace_startstop(_stp_utt, 0, &utt_seq); -#endif + dbug_trans(1, "*** calling _stp_transport_data_fs_stop ***\n"); + _stp_transport_data_fs_stop(); dbug_trans(1, "ctl_send STP_EXIT\n"); if (send_exit) @@ -236,9 +233,9 @@ static void _stp_transport_close(void) if (_stp_utt) utt_trace_remove(_stp_utt); #endif /* #if 0 */ + _stp_transport_fs_close(); _stp_print_cleanup(); /* free print buffers */ _stp_mem_debug_done(); - _stp_transport_fs_close(); dbug_trans(1, "---- CLOSED ----\n"); } @@ -317,10 +314,8 @@ static int _stp_transport_init(void) if (_stp_print_init() < 0) goto err2; -#if 0 /* start transport */ - utt_trace_startstop(_stp_utt, 1, &utt_seq); -#endif /* #if 0 */ + _stp_transport_data_fs_start(); /* create workqueue of kernel threads */ _stp_wq = create_workqueue("systemtap"); diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index c560be5d..df2d496d 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -74,6 +74,20 @@ static int _stp_bufsize; */ static int _stp_transport_data_fs_init(void); +/* + * _stp_transport_data_fs_start + * + * This function actually starts the transport. + */ +static void _stp_transport_data_fs_start(void); + +/* + * _stp_transport_data_fs_start + * + * This function stops the transport without doing any cleanup. + */ +static void _stp_transport_data_fs_stop(void); + /* * _stp_transport_data_fs_close * -- cgit From af274e5bd4593fa79c0489e0b6105f4bd23310c8 Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 3 Jun 2009 15:20:46 -0500 Subject: Make sure all DEBUG_TRANS output uses printk. * runtime/transport/control.c (_stp_ctl_write_cmd): Calls dbug_trans2 instead of _dbug (so that printk is used instead of the transport itself). (_stp_ctl_write_dbug): Ditto. * runtime/debug.h (dbug_trans2): New macro. --- runtime/debug.h | 6 ++++++ runtime/transport/control.c | 28 +++++++++++++++------------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/runtime/debug.h b/runtime/debug.h index ce0c3943..5c9cca74 100644 --- a/runtime/debug.h +++ b/runtime/debug.h @@ -38,8 +38,14 @@ printk(args); \ } \ } while (0) + +#define dbug_trans2(args...) do { \ + printk("%s:%d ",__FUNCTION__, __LINE__); \ + printk(args); \ + } while (0) #else #define dbug_trans(level, args...) ; +#define dbug_trans2(args...) ; #endif #ifdef DEBUG_UNWIND /* stack unwinder */ diff --git a/runtime/transport/control.c b/runtime/transport/control.c index 11338eb2..35130f0f 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -37,7 +37,8 @@ static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, siz #ifdef DEBUG_TRANS if (type < STP_MAX_CMD) - _dbug("Got %s. len=%d\n", _stp_command_name[type], (int)count); + dbug_trans2("Got %s. len=%d\n", _stp_command_name[type], + (int)count); #endif switch (type) { @@ -84,45 +85,46 @@ static void _stp_ctl_write_dbug(int type, void *data, int len) char buf[64]; switch (type) { case STP_START: - _dbug("sending STP_START\n"); + dbug_trans2("sending STP_START\n"); break; case STP_EXIT: - _dbug("sending STP_EXIT\n"); + dbug_trans2("sending STP_EXIT\n"); break; case STP_OOB_DATA: snprintf(buf, sizeof(buf), "%s", (char *)data); - _dbug("sending %d bytes of STP_OOB_DATA: %s\n", len, buf); + dbug_trans2("sending %d bytes of STP_OOB_DATA: %s\n", len, + buf); break; case STP_SYSTEM: snprintf(buf, sizeof(buf), "%s", (char *)data); - _dbug("sending STP_SYSTEM: %s\n", buf); + dbug_trans2("sending STP_SYSTEM: %s\n", buf); break; case STP_TRANSPORT: - _dbug("sending STP_TRANSPORT\n"); + dbug_trans2("sending STP_TRANSPORT\n"); break; case STP_CONNECT: - _dbug("sending STP_CONNECT\n"); + dbug_trans2("sending STP_CONNECT\n"); break; case STP_DISCONNECT: - _dbug("sending STP_DISCONNECT\n"); + dbug_trans2("sending STP_DISCONNECT\n"); break; case STP_BULK: - _dbug("sending STP_BULK\n"); + dbug_trans2("sending STP_BULK\n"); break; case STP_READY: case STP_RELOCATION: case STP_BUF_INFO: case STP_SUBBUFS_CONSUMED: - _dbug("sending old message\n"); + dbug_trans2("sending old message\n"); break; case STP_REALTIME_DATA: - _dbug("sending %d bytes of STP_REALTIME_DATA\n", len); + dbug_trans2("sending %d bytes of STP_REALTIME_DATA\n", len); break; case STP_REQUEST_EXIT: - _dbug("sending STP_REQUEST_EXIT\n"); + dbug_trans2("sending STP_REQUEST_EXIT\n"); break; default: - _dbug("ERROR: unknown message type: %d\n", type); + dbug_trans2("ERROR: unknown message type: %d\n", type); break; } } -- cgit From 0bd709c3a8ff717f3ad78fdc079ce0468bec3ffa Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 28 May 2009 10:58:17 -0500 Subject: Avoid 1 case of holding a semaphore while mmap callbacks are being made. * runtime/task_finder.c (__stp_call_mmap_callbacks_with_addr): Renamed from __stp_call_mmap_callbacks_with_vma(). Also added some code from __stp_utrace_task_finder_target_syscall_exit() that locks the 'mmap_sem' semaphore. This avoids holding the semaphore while the mmap callbacks are made. (__stp_utrace_task_finder_target_syscall_exit): Just calls __stp_call_mmap_callbacks_with_addr() in the mmap case. --- runtime/task_finder.c | 132 ++++++++++++++++++++++++++++---------------------- 1 file changed, 75 insertions(+), 57 deletions(-) diff --git a/runtime/task_finder.c b/runtime/task_finder.c index f5e059ca..b35192a2 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -580,43 +580,90 @@ __stp_call_mmap_callbacks(struct stap_task_finder_target *tgt, } } + +static struct vm_area_struct * +__stp_find_file_based_vma(struct mm_struct *mm, unsigned long addr) +{ + struct vm_area_struct *vma = find_vma(mm, addr); + + // I'm not positive why the checking for vm_start > addr is + // necessary, but it seems to be (sometimes find_vma() returns + // a vma that addr doesn't belong to). + if (vma && (vma->vm_file == NULL || vma->vm_start > addr)) + vma = NULL; + return vma; +} + + static void -__stp_call_mmap_callbacks_with_vma(struct stap_task_finder_target *tgt, - struct task_struct *tsk, - struct vm_area_struct *vma) +__stp_call_mmap_callbacks_with_addr(struct stap_task_finder_target *tgt, + struct task_struct *tsk, + unsigned long addr) { - char *mmpath_buf; - char *mmpath; - int rc; + struct mm_struct *mm; + struct vm_area_struct *vma; + char *mmpath_buf = NULL; + char *mmpath = NULL; + long err; + unsigned long length; + unsigned long offset; + unsigned long vm_flags; - // Allocate space for a path - mmpath_buf = _stp_kmalloc(PATH_MAX); - if (mmpath_buf == NULL) { - _stp_error("Unable to allocate space for path"); + mm = get_task_mm(tsk); + if (! mm) return; - } - // Grab the path associated with this vma. + down_read(&mm->mmap_sem); + vma = __stp_find_file_based_vma(mm, addr); + if (vma) { + // Cache information we need from the vma + addr = vma->vm_start; + length = vma->vm_end - vma->vm_start; + offset = (vma->vm_pgoff << PAGE_SHIFT); + vm_flags = vma->vm_flags; + + // Allocate space for a path + mmpath_buf = _stp_kmalloc(PATH_MAX); + if (mmpath_buf == NULL) { + _stp_error("Unable to allocate space for path"); + } + else { + // Grab the path associated with this vma. #ifdef STAPCONF_DPATH_PATH - mmpath = d_path(&(vma->vm_file->f_path), mmpath_buf, PATH_MAX); + mmpath = d_path(&(vma->vm_file->f_path), mmpath_buf, + PATH_MAX); #else - mmpath = d_path(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt, - mmpath_buf, PATH_MAX); + mmpath = d_path(vma->vm_file->f_dentry, + vma->vm_file->f_vfsmnt, mmpath_buf, + PATH_MAX); #endif - if (mmpath == NULL || IS_ERR(mmpath)) { - rc = -PTR_ERR(mmpath); - _stp_error("Unable to get path (error %d) for pid %d", - rc, (int)tsk->pid); - } - else { - __stp_call_mmap_callbacks(tgt, tsk, mmpath, vma->vm_start, - vma->vm_end - vma->vm_start, - (vma->vm_pgoff << PAGE_SHIFT), - vma->vm_flags); + if (mmpath == NULL || IS_ERR(mmpath)) { + long err = ((mmpath == NULL) ? 0 + : -PTR_ERR(mmpath)); + _stp_error("Unable to get path (error %ld) for pid %d", + err, (int)tsk->pid); + mmpath = NULL; + } + } } - _stp_kfree(mmpath_buf); + + // At this point, we're done with the vma (assuming we found + // one). We can't hold the 'mmap_sem' semaphore while making + // callbacks. + up_read(&mm->mmap_sem); + + if (mmpath) + __stp_call_mmap_callbacks(tgt, tsk, mmpath, addr, + length, offset, vm_flags); + + // Cleanup. + if (mmpath_buf) + _stp_kfree(mmpath_buf); + mmput(mm); + return; } + static inline void __stp_call_munmap_callbacks(struct stap_task_finder_target *tgt, struct task_struct *tsk, unsigned long addr, @@ -1055,19 +1102,6 @@ utftq_out: } -static struct vm_area_struct * -__stp_find_file_based_vma(struct mm_struct *mm, unsigned long addr) -{ - struct vm_area_struct *vma = find_vma(mm, addr); - - // I'm not positive why the checking for vm_start > addr is - // necessary, but it seems to be (sometimes find_vma() returns - // a vma that addr doesn't belong to). - if (vma && (vma->vm_file == NULL || vma->vm_start > addr)) - vma = NULL; - return vma; -} - #ifdef UTRACE_ORIG_VERSION static u32 __stp_utrace_task_finder_target_syscall_entry(struct utrace_attached_engine *engine, @@ -1194,24 +1228,8 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, } else if (entry->syscall_no == MMAP_SYSCALL_NO(tsk) || entry->syscall_no == MMAP2_SYSCALL_NO(tsk)) { - struct mm_struct *mm; - - mm = get_task_mm(tsk); - if (mm) { - struct vm_area_struct *vma; - - down_read(&mm->mmap_sem); - vma = __stp_find_file_based_vma(mm, rv); - - // Call the callbacks - if (vma) { - __stp_call_mmap_callbacks_with_vma(tgt, tsk, - vma); - } - - up_read(&mm->mmap_sem); - mmput(mm); - } + // Call the callbacks + __stp_call_mmap_callbacks_with_addr(tgt, tsk, rv); } else { // mprotect // Call the callbacks -- cgit From b56f0c8b802fbdf93f40b4a233095ea970cfed2b Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 1 Jun 2009 12:20:08 -0500 Subject: Avoid holding semaphore while making mmap callbacks. * runtime/task_finder.c (__stp_call_mmap_callbacks_for_task): Grabs the 'mmap_sem' sempaphore. Caches vma information, releases the semaphore, then makes mmap callbacks. (__stp_utrace_task_finder_target_quiesce): Calls __stp_call_mmap_callbacks_for_task() to make mmap callbacks on initial attach to a task. --- runtime/task_finder.c | 182 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 130 insertions(+), 52 deletions(-) diff --git a/runtime/task_finder.c b/runtime/task_finder.c index b35192a2..dab56170 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -983,6 +983,135 @@ __stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine, return UTRACE_DETACH; } +static void +__stp_call_mmap_callbacks_for_task(struct stap_task_finder_target *tgt, + struct task_struct *tsk) +{ + struct mm_struct *mm; + char *mmpath_buf; + char *mmpath; + struct vm_area_struct *vma; + int file_based_vmas = 0; + struct vma_cache_t { +#ifdef STAPCONF_DPATH_PATH + struct path *f_path; +#else + struct dentry *f_dentry; + struct vfsmount *f_vfsmnt; +#endif + unsigned long addr; + unsigned long length; + unsigned long offset; + unsigned long vm_flags; + }; + struct vma_cache_t *vma_cache = NULL; + struct vma_cache_t *vma_cache_p; + + /* Call the mmap_callback for every vma associated with + * a file. */ + mm = get_task_mm(tsk); + if (! mm) + return; + + // Allocate space for a path + mmpath_buf = _stp_kmalloc(PATH_MAX); + if (mmpath_buf == NULL) { + mmput(mm); + _stp_error("Unable to allocate space for path"); + return; + } + + down_read(&mm->mmap_sem); + + // First find the number of file-based vmas. + vma = mm->mmap; + while (vma) { + if (vma->vm_file) + file_based_vmas++; + vma = vma->vm_next; + } + + // Now allocate an array to cache vma information in. + if (file_based_vmas > 0) + vma_cache = _stp_kmalloc(sizeof(struct vma_cache_t) + * file_based_vmas); + if (vma_cache != NULL) { + // Loop through the vmas again, and cache needed information. + vma = mm->mmap; + vma_cache_p = vma_cache; + while (vma) { + if (vma->vm_file) { +#ifdef STAPCONF_DPATH_PATH + // Notice we're increasing the reference + // count for 'f_path'. This way it won't + // get deleted from out under us. + vma_cache_p->f_path = &(vma->vm_file->f_path); + path_get(vma_cache_p->f_path); +#else + // Notice we're increasing the reference + // count for 'f_dentry' and 'f_vfsmnt'. + // This way they won't get deleted from + // out under us. + vma_cache_p->f_dentry = vma->vm_file->f_dentry; + dget(vma_cache_p->f_path); + vma_cache_p->f_vfsmnt = vma->vm_file->f_vfsmnt; + mntget(vma_cache_p->f_vfsmnt); +#endif + vma_cache_p->addr = vma->vm_start; + vma_cache_p->length = vma->vm_end - vma->vm_start; + vma_cache_p->offset = (vma->vm_pgoff << PAGE_SHIFT); + vma_cache_p->vm_flags = vma->vm_flags; + vma_cache_p++; + } + vma = vma->vm_next; + } + } + + // At this point, we're done with the vmas (assuming we found + // any). We can't hold the 'mmap_sem' semaphore while making + // callbacks. + up_read(&mm->mmap_sem); + + if (vma_cache) { + int i; + + // Loop over our cached information and make callbacks + // based on it. + vma_cache_p = vma_cache; + for (i = 0; i < file_based_vmas; i++) { +#ifdef STAPCONF_DPATH_PATH + mmpath = d_path(vma_cache_p->f_path, mmpath_buf, + PATH_MAX); + path_put(vma_cache_p->f_path); +#else + mmpath = d_path(vma_cache_p->f_dentry, + vma_cache_p->f_vfsmnt, mmpath_buf, + PATH_MAX); + dput(vma_cache_p->f_dentry); + mntput(vma_cache_p->f_vfsmnt); +#endif + if (mmpath == NULL || IS_ERR(mmpath)) { + long err = ((mmpath == NULL) ? 0 + : -PTR_ERR(mmpath)); + _stp_error("Unable to get path (error %ld) for pid %d", + err, (int)tsk->pid); + } + else { + __stp_call_mmap_callbacks(tgt, tsk, mmpath, + vma_cache_p->addr, + vma_cache_p->length, + vma_cache_p->offset, + vma_cache_p->vm_flags); + } + vma_cache_p++; + } + _stp_kfree(vma_cache); + } + + mmput(mm); /* We're done with mm */ + _stp_kfree(mmpath_buf); +} + #ifdef UTRACE_ORIG_VERSION static u32 __stp_utrace_task_finder_target_quiesce(struct utrace_attached_engine *engine, @@ -1043,60 +1172,9 @@ __stp_utrace_task_finder_target_quiesce(enum utrace_resume_action action, don't bother inform map callback clients about its memory map, since they will simply duplicate each other. */ if (tgt->mmap_events == 1 && tsk->tgid == tsk->pid) { - struct mm_struct *mm; - char *mmpath_buf; - char *mmpath; - struct vm_area_struct *vma; - int rc; - - /* Call the mmap_callback for every vma associated with - * a file. */ - mm = get_task_mm(tsk); - if (! mm) - goto utftq_out; - - // Allocate space for a path - mmpath_buf = _stp_kmalloc(PATH_MAX); - if (mmpath_buf == NULL) { - mmput(mm); - _stp_error("Unable to allocate space for path"); - goto utftq_out; - } - - down_read(&mm->mmap_sem); - vma = mm->mmap; - while (vma) { - if (vma->vm_file) { -#ifdef STAPCONF_DPATH_PATH - mmpath = d_path(&(vma->vm_file->f_path), - mmpath_buf, PATH_MAX); -#else - mmpath = d_path(vma->vm_file->f_dentry, - vma->vm_file->f_vfsmnt, - mmpath_buf, PATH_MAX); -#endif - if (mmpath) { - __stp_call_mmap_callbacks(tgt, tsk, - mmpath, - vma->vm_start, - vma->vm_end - vma->vm_start, - (vma->vm_pgoff - << PAGE_SHIFT), - vma->vm_flags); - } - else { - _stp_dbug(__FUNCTION__, __LINE__, - "no mmpath?\n"); - } - } - vma = vma->vm_next; - } - up_read(&mm->mmap_sem); - mmput(mm); /* We're done with mm */ - _stp_kfree(mmpath_buf); + __stp_call_mmap_callbacks_for_task(tgt, tsk); } -utftq_out: __stp_tf_handler_end(); return UTRACE_RESUME; } -- cgit From 43229357282fd51eb1a3c7742932068873c27270 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 2 Jun 2009 11:21:24 -0500 Subject: Fixed cut-and-paste error. * runtime/task_finder.c (__stp_call_mmap_callbacks_for_task): Fixed cut-and-paste error. --- runtime/task_finder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/task_finder.c b/runtime/task_finder.c index dab56170..672b21f1 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -1053,7 +1053,7 @@ __stp_call_mmap_callbacks_for_task(struct stap_task_finder_target *tgt, // This way they won't get deleted from // out under us. vma_cache_p->f_dentry = vma->vm_file->f_dentry; - dget(vma_cache_p->f_path); + dget(vma_cache_p->f_dentry); vma_cache_p->f_vfsmnt = vma->vm_file->f_vfsmnt; mntget(vma_cache_p->f_vfsmnt); #endif -- cgit From d05b7a1c363c30c7fcd9d163f457c1ed80d28f19 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 12 Jun 2009 13:20:57 -0500 Subject: Fixed non-bulkmode output on smp systems using transport version 2. * runtime/transport/relay_v2.c (__stp_relay_create_buf_file_callback): Set the 'is_global' return parameter so that smp systems work correctly. --- runtime/transport/relay_v2.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index 16b5afa1..246c4965 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -204,6 +204,21 @@ __stp_relay_create_buf_file_callback(const char *filename, { struct dentry *file = debugfs_create_file(filename, mode, parent, buf, &relay_file_operations); + /* + * Here's what 'is_global' does (from linux/relay.h): + * + * Setting the is_global outparam to a non-zero value will + * cause relay_open() to create a single global buffer rather + * than the default set of per-cpu buffers. + */ + if (is_global) { +#ifdef STP_BULKMODE + *is_global = 0; +#else + *is_global = 1; +#endif + } + if (IS_ERR(file)) { file = NULL; } -- cgit From d2309c6c3fb97cc0c8931b59e33fe18820b63c5d Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Thu, 18 Jun 2009 17:54:15 +0200 Subject: PR10273 Correctly adjust libdw address for dwfl dwarf bias. * dwflpp.cxx (relocate_address): Adjust reloc_addr at start, not afterwards. --- dwflpp.cxx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dwflpp.cxx b/dwflpp.cxx index e01c6974..61627e16 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -2341,11 +2341,13 @@ dwflpp::get_blacklist_section(Dwarf_Addr addr) Dwarf_Addr -dwflpp::relocate_address(Dwarf_Addr addr, +dwflpp::relocate_address(Dwarf_Addr dw_addr, string& reloc_section, string& blacklist_section) { - Dwarf_Addr reloc_addr = addr; + // PR10273 + // libdw address, so adjust for bias gotten from dwfl_module_getdwarf + Dwarf_Addr reloc_addr = dw_addr + module_bias; if (!module) { assert(module_name == TOK_KERNEL); @@ -2364,14 +2366,13 @@ dwflpp::relocate_address(Dwarf_Addr addr, if (reloc_section == "" && dwfl_module_relocations (module) == 1) { - blacklist_section = get_blacklist_section(addr); + blacklist_section = get_blacklist_section(dw_addr); reloc_section = ".dynamic"; - reloc_addr += module_bias; // PR10273 } } else { - blacklist_section = get_blacklist_section(addr); + blacklist_section = get_blacklist_section(dw_addr); reloc_section = ".absolute"; } return reloc_addr; -- 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/relay_v2.c | 2 +- runtime/transport/relayfs.c | 2 +- runtime/transport/ring_buffer.c | 4 ++++ runtime/transport/transport.c | 15 ++------------- runtime/transport/transport.h | 17 +++++++++-------- 5 files changed, 17 insertions(+), 23 deletions(-) diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index 246c4965..aa6f7b99 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -147,7 +147,7 @@ static void __stp_relay_timer_init(void) smp_mb(); } -static void stp_relay_set_overwrite(int overwrite) +static void _stp_transport_data_fs_overwrite(int overwrite) { _stp_relay_data.overwrite_flag = overwrite; } diff --git a/runtime/transport/relayfs.c b/runtime/transport/relayfs.c index 191b932f..c557efbc 100644 --- a/runtime/transport/relayfs.c +++ b/runtime/transport/relayfs.c @@ -136,7 +136,7 @@ err: return rc; } -static void stp_relay_set_overwrite(int overwrite) +static void _stp_transport_data_fs_overwrite(int overwrite) { _stp_relay_data.rchan->overwrite = overwrite; } 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. */ +} diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 84959f71..a1d90dcf 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -20,13 +20,6 @@ #include #include -#if 0 -static void utt_set_overwrite(int overwrite) -{ - return; -} -#endif - static int _stp_exit_flag = 0; static uid_t _stp_uid = 0; @@ -166,10 +159,8 @@ static void _stp_detach(void) _stp_ctl_attached = 0; _stp_pid = 0; -#if 0 if (!_stp_exit_flag) - utt_set_overwrite(1); -#endif + _stp_transport_data_fs_overwrite(1); cancel_delayed_work(&_stp_work); wake_up_interruptible(&_stp_ctl_wq); @@ -183,9 +174,7 @@ static void _stp_attach(void) dbug_trans(1, "attach\n"); _stp_ctl_attached = 1; _stp_pid = current->pid; -#if 0 - utt_set_overwrite(0); -#endif + _stp_transport_data_fs_overwrite(0); queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); } diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index df2d496d..b3d15ef3 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -11,19 +11,11 @@ /* amount of data a print can send. */ #define STP_BUFFER_SIZE 8192 -struct utt_trace; - static int _stp_ctl_write(int type, void *data, unsigned len); static int _stp_transport_init(void); static void _stp_transport_close(void); -static inline void *utt_reserve(struct utt_trace *utt, size_t length) -{ - return NULL; -} - - /* STP_CTL_BUFFER_SIZE is the maximum size of a message */ /* exchanged on the control channel. */ #if STP_TRANSPORT_VERSION == 1 @@ -96,6 +88,15 @@ static void _stp_transport_data_fs_stop(void); */ static void _stp_transport_data_fs_close(void); +/* + * _stp_transport_data_fs_overwrite - set data overwrite mode + * overwrite: boolean + * + * When in overwrite mode and the transport buffers are full, older + * data gets overwritten. + */ +static void _stp_transport_data_fs_overwrite(int overwrite); + /* * _stp_data_write_reserve - reserve bytes * size_request: number of bytes to reserve -- cgit From 905728a036bf9d5cf0c21d684ad53882489c82c8 Mon Sep 17 00:00:00 2001 From: William Cohen Date: Thu, 18 Jun 2009 16:14:42 -0400 Subject: Check in sk_stream_wait_memory.stp example. --- testsuite/systemtap.examples/index.html | 3 ++ testsuite/systemtap.examples/index.txt | 9 ++++++ testsuite/systemtap.examples/keyword-index.html | 12 ++++++++ testsuite/systemtap.examples/keyword-index.txt | 36 ++++++++++++++++++++++ .../network/sk_stream_wait_memory.meta | 13 ++++++++ .../network/sk_stream_wait_memory.stp | 25 +++++++++++++++ 6 files changed, 98 insertions(+) create mode 100644 testsuite/systemtap.examples/network/sk_stream_wait_memory.meta create mode 100755 testsuite/systemtap.examples/network/sk_stream_wait_memory.stp diff --git a/testsuite/systemtap.examples/index.html b/testsuite/systemtap.examples/index.html index b2ed3a3a..a5fddb4e 100644 --- a/testsuite/systemtap.examples/index.html +++ b/testsuite/systemtap.examples/index.html @@ -97,6 +97,9 @@ keywords: NETWORK network/nettop.stp - Periodic Listing of Processes Using Network Interfaces
keywords: NETWORK TRAFFIC PER-PROCESS

Every five seconds the nettop.stp script prints out a list of processed (PID and command) with the number of packets sent/received and the amount of data sent/received by the process during that interval.

+
  • network/sk_stream_wait_memory.stp - Track Start and Stop of Processes Due to Network Buffer Space
    +keywords: NETWORK TCP BUFFER MEMORY
    +

    The sk_stream-wait_memory.stp prints a time stamp, executable, and pid each time a process blocks due to the send buffer being full. A similar entry is printed each time a process continues because there is room in the buffer.

  • network/socket-trace.stp - Trace Functions called in Network Socket Code
    keywords: NETWORK SOCKET

    The script instrument each of the functions inn the Linux kernel's net/socket.c file. The script prints out trace. The first element of a line is time delta in microseconds from the previous entry. This is followed by the command name and the PID. The "->" and "<-" indicates function entry and function exit, respectively. The last element of the line is the function name.

  • diff --git a/testsuite/systemtap.examples/index.txt b/testsuite/systemtap.examples/index.txt index 91fc66ae..95e81435 100644 --- a/testsuite/systemtap.examples/index.txt +++ b/testsuite/systemtap.examples/index.txt @@ -176,6 +176,15 @@ keywords: network traffic per-process interval. +network/sk_stream_wait_memory.stp - Track Start and Stop of Processes Due to Network Buffer Space +keywords: network tcp buffer memory + + The sk_stream-wait_memory.stp prints a time stamp, executable, and + pid each time a process blocks due to the send buffer being full. A + similar entry is printed each time a process continues because there + is room in the buffer. + + network/socket-trace.stp - Trace Functions called in Network Socket Code keywords: network socket diff --git a/testsuite/systemtap.examples/keyword-index.html b/testsuite/systemtap.examples/keyword-index.html index 7306c164..e144337c 100644 --- a/testsuite/systemtap.examples/keyword-index.html +++ b/testsuite/systemtap.examples/keyword-index.html @@ -57,6 +57,9 @@ keywords: IO network/dropwatch.stp - Watch Where Socket Buffers are Freed in the Kernel
    keywords: NETWORK TRACEPOINT BUFFER FREE

    Every five seconds the dropwatch.stp script lists the number of socket buffers freed at locations in the kernel.

    +
  • network/sk_stream_wait_memory.stp - Track Start and Stop of Processes Due to Network Buffer Space
    +keywords: NETWORK TCP BUFFER MEMORY
    +

    The sk_stream-wait_memory.stp prints a time stamp, executable, and pid each time a process blocks due to the send buffer being full. A similar entry is printed each time a process continues because there is room in the buffer.

  • CALLGRAPH

      @@ -162,6 +165,9 @@ keywords: MEMORY
    • memory/pfaults.stp - Generate Log of Major and Minor Page Faults
      keywords: MEMORY

      The pfaults.stp script generates a simple log for each major and minor page fault that occurs on the system. Each line contains a timestamp (in microseconds) when the page fault servicing was completed, the pid of the process, the address of the page fault, the type of access (read or write), the type of fault (major or minor), and the elapsed time for page fault. This log can be examined to determine where the page faults are occuring.

    • +
    • network/sk_stream_wait_memory.stp - Track Start and Stop of Processes Due to Network Buffer Space
      +keywords: NETWORK TCP BUFFER MEMORY
      +

      The sk_stream-wait_memory.stp prints a time stamp, executable, and pid each time a process blocks due to the send buffer being full. A similar entry is printed each time a process continues because there is room in the buffer.

    MONITOR

      @@ -177,6 +183,9 @@ keywords: NETWORK network/nettop.stp - Periodic Listing of Processes Using Network Interfaces
      keywords: NETWORK TRAFFIC PER-PROCESS

      Every five seconds the nettop.stp script prints out a list of processed (PID and command) with the number of packets sent/received and the amount of data sent/received by the process during that interval.

      +
    • network/sk_stream_wait_memory.stp - Track Start and Stop of Processes Due to Network Buffer Space
      +keywords: NETWORK TCP BUFFER MEMORY
      +

      The sk_stream-wait_memory.stp prints a time stamp, executable, and pid each time a process blocks due to the send buffer being full. A similar entry is printed each time a process continues because there is room in the buffer.

    • network/socket-trace.stp - Trace Functions called in Network Socket Code
      keywords: NETWORK SOCKET

      The script instrument each of the functions inn the Linux kernel's net/socket.c file. The script prints out trace. The first element of a line is time delta in microseconds from the previous entry. This is followed by the command name and the PID. The "->" and "<-" indicates function entry and function exit, respectively. The last element of the line is the function name.

    • @@ -303,6 +312,9 @@ keywords: SYSCALL TCP
        +
      • network/sk_stream_wait_memory.stp - Track Start and Stop of Processes Due to Network Buffer Space
        +keywords: NETWORK TCP BUFFER MEMORY
        +

        The sk_stream-wait_memory.stp prints a time stamp, executable, and pid each time a process blocks due to the send buffer being full. A similar entry is printed each time a process continues because there is room in the buffer.

      • network/tcp_connections.stp - Track Creation of Incoming TCP Connections
        keywords: NETWORK TCP SOCKET

        The tcp_connections.stp script prints information for each new incoming TCP connection accepted by the computer. The information includes the UID, the command accepting the connection, the PID of the command, the port the connection is on, and the IP address of the originator of the request.

      • diff --git a/testsuite/systemtap.examples/keyword-index.txt b/testsuite/systemtap.examples/keyword-index.txt index eee89e22..8305e208 100644 --- a/testsuite/systemtap.examples/keyword-index.txt +++ b/testsuite/systemtap.examples/keyword-index.txt @@ -39,6 +39,15 @@ keywords: network tracepoint buffer free socket buffers freed at locations in the kernel. +network/sk_stream_wait_memory.stp - Track Start and Stop of Processes Due to Network Buffer Space +keywords: network tcp buffer memory + + The sk_stream-wait_memory.stp prints a time stamp, executable, and + pid each time a process blocks due to the send buffer being full. A + similar entry is printed each time a process continues because there + is room in the buffer. + + = CALLGRAPH = general/para-callgraph.stp - Callgraph tracing with arguments @@ -275,6 +284,15 @@ keywords: memory determine where the page faults are occuring. +network/sk_stream_wait_memory.stp - Track Start and Stop of Processes Due to Network Buffer Space +keywords: network tcp buffer memory + + The sk_stream-wait_memory.stp prints a time stamp, executable, and + pid each time a process blocks due to the send buffer being full. A + similar entry is printed each time a process continues because there + is room in the buffer. + + = MONITOR = io/ttyspy.stp - Monitor tty typing. @@ -303,6 +321,15 @@ keywords: network traffic per-process interval. +network/sk_stream_wait_memory.stp - Track Start and Stop of Processes Due to Network Buffer Space +keywords: network tcp buffer memory + + The sk_stream-wait_memory.stp prints a time stamp, executable, and + pid each time a process blocks due to the send buffer being full. A + similar entry is printed each time a process continues because there + is room in the buffer. + + network/socket-trace.stp - Trace Functions called in Network Socket Code keywords: network socket @@ -624,6 +651,15 @@ keywords: syscall wait4 = TCP = +network/sk_stream_wait_memory.stp - Track Start and Stop of Processes Due to Network Buffer Space +keywords: network tcp buffer memory + + The sk_stream-wait_memory.stp prints a time stamp, executable, and + pid each time a process blocks due to the send buffer being full. A + similar entry is printed each time a process continues because there + is room in the buffer. + + network/tcp_connections.stp - Track Creation of Incoming TCP Connections keywords: network tcp socket diff --git a/testsuite/systemtap.examples/network/sk_stream_wait_memory.meta b/testsuite/systemtap.examples/network/sk_stream_wait_memory.meta new file mode 100644 index 00000000..bc798f72 --- /dev/null +++ b/testsuite/systemtap.examples/network/sk_stream_wait_memory.meta @@ -0,0 +1,13 @@ +title: Track Start and Stop of Processes Due to Network Buffer Space +name: sk_stream_wait_memory.stp +version: 1.0 +author: Fabio Olive Leite at Red Hat +keywords: network tcp buffer memory +subsystem: kernel +status: production +exit: user-controlled +output: trace +scope: system-wide +description: The sk_stream-wait_memory.stp prints a time stamp, executable, and pid each time a process blocks due to the send buffer being full. A similar entry is printed each time a process continues because there is room in the buffer. +test_check: stap -p4 sk_stream_wait_memory.stp +test_installcheck: stap sk_stream_wait_memory.stp -c "sleep 1" diff --git a/testsuite/systemtap.examples/network/sk_stream_wait_memory.stp b/testsuite/systemtap.examples/network/sk_stream_wait_memory.stp new file mode 100755 index 00000000..159d77a6 --- /dev/null +++ b/testsuite/systemtap.examples/network/sk_stream_wait_memory.stp @@ -0,0 +1,25 @@ +# Simple probe to detect when a process is waiting for more socket send +# buffer memory. Usually means the process is doing writes larger than the +# socker send buffer size or there is a slow receiver at the other side. +# Increasing the socket's send buffer size might help decrease application +# latencies, but it might also make it worse, so buyer beware. +# +# Tipical output: timestamp in microseconds: procname(pid) event +# +# 1218230114875167: python(17631) blocked on full send buffer +# 1218230114876196: python(17631) recovered from full send buffer +# 1218230114876271: python(17631) blocked on full send buffer +# 1218230114876479: python(17631) recovered from full send buffer + +probe kernel.function("sk_stream_wait_memory") +{ + printf("%u: %s(%d) blocked on full send buffer\n", + gettimeofday_us(), execname(), pid()) +} + +probe kernel.function("sk_stream_wait_memory").return +{ + printf("%u: %s(%d) recovered from full send buffer\n", + gettimeofday_us(), execname(), pid()) +} + -- cgit From 7c0bbff77507c69b706af667ac33770fb6180cbb Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 18 Jun 2009 15:56:45 -0500 Subject: Removed unused code (and all references to 'utt'). --- runtime/transport/transport.c | 52 ------------------------------------------- 1 file changed, 52 deletions(-) diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index a1d90dcf..7f844f5d 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -31,9 +31,6 @@ static int _stp_ctl_attached = 0; static pid_t _stp_target = 0; static int _stp_probes_started = 0; -#if 1 -//static struct utt_trace *_stp_utt = NULL; -//static unsigned int utt_seq = 1; #include "control.h" #if STP_TRANSPORT_VERSION == 1 #include "relayfs.c" @@ -48,11 +45,6 @@ static int _stp_probes_started = 0; #endif #include "control.c" -#else /* #if 0 */ -#include "control.h" -#include "debugfs.c" -#include "control.c" -#endif /* if 0 */ static unsigned _stp_nsubbufs = 8; static unsigned _stp_subbuf_size = 65536*4; @@ -218,10 +210,6 @@ static void _stp_transport_close(void) _stp_cleanup_and_exit(0); destroy_workqueue(_stp_wq); _stp_unregister_ctl_channel(); -#if 0 - if (_stp_utt) - utt_trace_remove(_stp_utt); -#endif /* #if 0 */ _stp_transport_fs_close(); _stp_print_cleanup(); /* free print buffers */ _stp_mem_debug_done(); @@ -229,25 +217,6 @@ static void _stp_transport_close(void) dbug_trans(1, "---- CLOSED ----\n"); } -#if 0 -static struct utt_trace *_stp_utt_open(void) -{ - struct utt_trace_setup utts; - strlcpy(utts.root, "systemtap", sizeof(utts.root)); - strlcpy(utts.name, THIS_MODULE->name, sizeof(utts.name)); - utts.buf_size = _stp_subbuf_size; - utts.buf_nr = _stp_nsubbufs; - -#ifdef STP_BULKMODE - utts.is_global = 0; -#else - utts.is_global = 1; -#endif - - return utt_trace_setup(&utts); -} -#endif /* #if 0 */ - /** * _stp_transport_init() is called from the module initialization. * It does the bare minimum to exchange commands with staprun @@ -263,8 +232,6 @@ static int _stp_transport_init(void) _stp_gid = current_gid(); #endif -// DRS: is RELAY_GUEST/RELAY_HOST documented? does it work? are there -// test cases? #ifdef RELAY_GUEST /* Guest scripts use relay only for reporting warnings and errors */ _stp_subbuf_size = 65536; @@ -285,16 +252,6 @@ static int _stp_transport_init(void) if (_stp_transport_fs_init(THIS_MODULE->name) != 0) goto err0; -#if 0 -#if !defined (STP_OLD_TRANSPORT) || defined (STP_BULKMODE) - /* open utt (relayfs) channel to send data to userspace */ - _stp_utt = _stp_utt_open(); - if (!_stp_utt) - goto err0; -#endif -#else /* #if 0 */ -#endif /* #if 0 */ - /* create control channel */ if (_stp_register_ctl_channel() < 0) goto err1; @@ -318,21 +275,12 @@ static int _stp_transport_init(void) return 0; err3: - dbug_trans(1, "err3\n"); _stp_print_cleanup(); err2: - dbug_trans(1, "err2\n"); _stp_unregister_ctl_channel(); err1: -#if 0 - if (_stp_utt) - utt_trace_remove(_stp_utt); -#else - dbug_trans(1, "err1\n"); _stp_transport_fs_close(); -#endif /* #if 0 */ err0: - dbug_trans(1, "err0\n"); return -1; } -- 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(-) 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 ed35c8ac5bc2da83fedfb53d0c283ee8c5c77f39 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 18 Jun 2009 17:19:29 -0400 Subject: PR10298: tweak global param initialization for NULL etc. * translate.cxx (translate_pass): Emit module_parm stuff at the very end. * testsuite/buildok/null.stp: New test. --- testsuite/buildok/null.stp | 5 +++++ translate.cxx | 13 +++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) create mode 100755 testsuite/buildok/null.stp diff --git a/testsuite/buildok/null.stp b/testsuite/buildok/null.stp new file mode 100755 index 00000000..9bcaf3f6 --- /dev/null +++ b/testsuite/buildok/null.stp @@ -0,0 +1,5 @@ +#! stap -p4 + +# PR10298 +global foo = 5 +probe begin { if (foo == NULL) log("hello") } diff --git a/translate.cxx b/translate.cxx index 518e5584..cc634555 100644 --- a/translate.cxx +++ b/translate.cxx @@ -5212,18 +5212,19 @@ translate_pass (systemtap_session& s) s.op->newline(-1) << "}"; s.op->assert_0_indent(); + emit_symbol_data (s); + + s.op->newline() << "MODULE_DESCRIPTION(\"systemtap-generated probe\");"; + s.op->newline() << "MODULE_LICENSE(\"GPL\");"; + s.op->assert_0_indent(); + + // PR10298: attempt to avoid collisions with symbols for (unsigned i=0; inewline(); s.up->emit_global_param (s.globals[i]); } s.op->assert_0_indent(); - - emit_symbol_data (s); - - s.op->newline() << "MODULE_DESCRIPTION(\"systemtap-generated probe\");"; - s.op->newline() << "MODULE_LICENSE(\"GPL\");"; - s.op->assert_0_indent(); } catch (const semantic_error& e) { -- 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/print_new.c | 5 ++--- runtime/transport/relay_v2.c | 11 +++++------ runtime/transport/relayfs.c | 11 +++++------ runtime/transport/ring_buffer.c | 16 ++++++++++++++-- runtime/transport/transport.h | 14 ++++++++++++++ 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/runtime/print_new.c b/runtime/print_new.c index 2d5a6e10..52017426 100644 --- a/runtime/print_new.c +++ b/runtime/print_new.c @@ -30,9 +30,8 @@ void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) pb->len = 0; -//DRS FIXME: this digs down too deep in internals -// if (unlikely(!_stp_utt || _stp_utt->trace_state != Utt_trace_running)) -// return; + if (unlikely(_stp_transport_get_state() != STP_TRANSPORT_RUNNING)) + return; #ifdef STP_BULKMODE #ifdef NO_PERCPU_HEADERS diff --git a/runtime/transport/relay_v2.c b/runtime/transport/relay_v2.c index aa6f7b99..65e9c59b 100644 --- a/runtime/transport/relay_v2.c +++ b/runtime/transport/relay_v2.c @@ -38,12 +38,6 @@ #define STP_RELAY_TIMER_INTERVAL ((HZ + 99) / 100) #endif -enum _stp_transport_state { - STP_TRANSPORT_STOPPED, - STP_TRANSPORT_INITIALIZED, - STP_TRANSPORT_RUNNING, -}; - struct _stp_relay_data_type { enum _stp_transport_state transport_state; struct rchan *rchan; @@ -147,6 +141,11 @@ static void __stp_relay_timer_init(void) smp_mb(); } +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) { _stp_relay_data.overwrite_flag = overwrite; diff --git a/runtime/transport/relayfs.c b/runtime/transport/relayfs.c index c557efbc..338b2771 100644 --- a/runtime/transport/relayfs.c +++ b/runtime/transport/relayfs.c @@ -23,12 +23,6 @@ #include #include -enum _stp_transport_state { - STP_TRANSPORT_STOPPED, - STP_TRANSPORT_INITIALIZED, - STP_TRANSPORT_RUNNING, -}; - struct _stp_relay_data_type { enum _stp_transport_state transport_state; struct rchan *rchan; @@ -136,6 +130,11 @@ err: return rc; } +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) { _stp_relay_data.rchan->overwrite = overwrite; 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. */ diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h index b3d15ef3..871e37b3 100644 --- a/runtime/transport/transport.h +++ b/runtime/transport/transport.h @@ -54,10 +54,24 @@ static int _stp_ctl_attached; static int _stp_bufsize; + +enum _stp_transport_state { + STP_TRANSPORT_STOPPED, + STP_TRANSPORT_INITIALIZED, + STP_TRANSPORT_RUNNING, +}; + /* * All transports must provide the following functions. */ +/* + * _stp_transport_get_state + * + * This function returns the current transport state. + */ +static enum _stp_transport_state _stp_transport_get_state(void); + /* * _stp_transport_data_fs_init * -- cgit From ac4f1eca71edee2feb2cbdad1a044549f30da023 Mon Sep 17 00:00:00 2001 From: David Smith Date: Thu, 18 Jun 2009 16:49:59 -0500 Subject: Cleanup. * runtime/print_old.c: Removed unneeded file. * runtime/print_flush.c: Renamed from print_new.c * runtime/print.c: Includes print_flush.c (instead of print_new.c). --- runtime/print.c | 2 +- runtime/print_flush.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++ runtime/print_new.c | 129 -------------------------------------------------- runtime/print_old.c | 55 --------------------- 4 files changed, 130 insertions(+), 185 deletions(-) create mode 100644 runtime/print_flush.c delete mode 100644 runtime/print_new.c delete mode 100644 runtime/print_old.c diff --git a/runtime/print.c b/runtime/print.c index d51c8108..69e04073 100644 --- a/runtime/print.c +++ b/runtime/print.c @@ -89,7 +89,7 @@ static void _stp_print_cleanup (void) #if !defined(RELAY_GUEST) -#include "print_new.c" +#include "print_flush.c" #if defined(RELAY_HOST) EXPORT_SYMBOL_GPL(EXPORT_FN(stp_print_flush)); #endif diff --git a/runtime/print_flush.c b/runtime/print_flush.c new file mode 100644 index 00000000..52017426 --- /dev/null +++ b/runtime/print_flush.c @@ -0,0 +1,129 @@ +/* -*- linux-c -*- + * Print Flush Function + * Copyright (C) 2007-2008 Red Hat Inc. + * + * This file is part of systemtap, and is free software. You can + * redistribute it and/or modify it under the terms of the GNU General + * Public License (GPL); either version 2, or (at your option) any + * later version. + */ + +/** Send the print buffer to the transport now. + * Output accumulates in the print buffer until it + * is filled, or this is called. This MUST be called before returning + * from a probe or accumulated output in the print buffer will be lost. + * + * @note Preemption must be disabled to use this. + */ + +static DEFINE_SPINLOCK(_stp_print_lock); + +void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) +{ + size_t len = pb->len; + void *entry = NULL; + + /* check to see if there is anything in the buffer */ + dbug_trans(1, "len = %zu\n", len); + if (likely(len == 0)) + return; + + pb->len = 0; + + if (unlikely(_stp_transport_get_state() != STP_TRANSPORT_RUNNING)) + return; + +#ifdef STP_BULKMODE +#ifdef NO_PERCPU_HEADERS + { + char *bufp = pb->buf; + + while (len > 0) { + size_t bytes_reserved; + + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); + _stp_data_write_commit(entry); + bufp += bytes_reserved; + len -= bytes_reserved; + } + else { + atomic_inc(&_stp_transport_failures); + break; + } + } + } + +#else /* !NO_PERCPU_HEADERS */ + + { + char *bufp = pb->buf; + struct _stp_trace t = { .sequence = _stp_seq_inc(), + .pdu_len = len}; + size_t bytes_reserved; + + bytes_reserved = _stp_data_write_reserve(sizeof(struct _stp_trace), &entry); + if (likely(entry && bytes_reserved > 0)) { + /* prevent unaligned access by using memcpy() */ + memcpy(_stp_data_entry_data(entry), &t, sizeof(t)); + _stp_data_write_commit(entry); + } + else { + atomic_inc(&_stp_transport_failures); + return; + } + + while (len > 0) { + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); + _stp_data_write_commit(entry); + bufp += bytes_reserved; + len -= bytes_reserved; + } + else { + atomic_inc(&_stp_transport_failures); + break; + } + } + } +#endif /* !NO_PERCPU_HEADERS */ + +#else /* !STP_BULKMODE */ + +#if STP_TRANSPORT_VERSION == 1 + + if (unlikely(_stp_ctl_write(STP_REALTIME_DATA, pb->buf, len) <= 0)) + atomic_inc (&_stp_transport_failures); + +#else /* STP_TRANSPORT_VERSION != 1 */ + { + unsigned long flags; + char *bufp = pb->buf; + + dbug_trans(1, "calling _stp_data_write...\n"); + spin_lock_irqsave(&_stp_print_lock, flags); + while (len > 0) { + size_t bytes_reserved; + + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); + _stp_data_write_commit(entry); + bufp += bytes_reserved; + len -= bytes_reserved; + } + else { + atomic_inc(&_stp_transport_failures); + break; + } + } + spin_unlock_irqrestore(&_stp_print_lock, flags); + } +#endif /* STP_TRANSPORT_VERSION != 1 */ +#endif /* !STP_BULKMODE */ +} diff --git a/runtime/print_new.c b/runtime/print_new.c deleted file mode 100644 index 52017426..00000000 --- a/runtime/print_new.c +++ /dev/null @@ -1,129 +0,0 @@ -/* -*- linux-c -*- - * Print Flush Function - * Copyright (C) 2007-2008 Red Hat Inc. - * - * This file is part of systemtap, and is free software. You can - * redistribute it and/or modify it under the terms of the GNU General - * Public License (GPL); either version 2, or (at your option) any - * later version. - */ - -/** Send the print buffer to the transport now. - * Output accumulates in the print buffer until it - * is filled, or this is called. This MUST be called before returning - * from a probe or accumulated output in the print buffer will be lost. - * - * @note Preemption must be disabled to use this. - */ - -static DEFINE_SPINLOCK(_stp_print_lock); - -void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) -{ - size_t len = pb->len; - void *entry = NULL; - - /* check to see if there is anything in the buffer */ - dbug_trans(1, "len = %zu\n", len); - if (likely(len == 0)) - return; - - pb->len = 0; - - if (unlikely(_stp_transport_get_state() != STP_TRANSPORT_RUNNING)) - return; - -#ifdef STP_BULKMODE -#ifdef NO_PERCPU_HEADERS - { - char *bufp = pb->buf; - - while (len > 0) { - size_t bytes_reserved; - - bytes_reserved = _stp_data_write_reserve(len, &entry); - if (likely(entry && bytes_reserved > 0)) { - memcpy(_stp_data_entry_data(entry), bufp, - bytes_reserved); - _stp_data_write_commit(entry); - bufp += bytes_reserved; - len -= bytes_reserved; - } - else { - atomic_inc(&_stp_transport_failures); - break; - } - } - } - -#else /* !NO_PERCPU_HEADERS */ - - { - char *bufp = pb->buf; - struct _stp_trace t = { .sequence = _stp_seq_inc(), - .pdu_len = len}; - size_t bytes_reserved; - - bytes_reserved = _stp_data_write_reserve(sizeof(struct _stp_trace), &entry); - if (likely(entry && bytes_reserved > 0)) { - /* prevent unaligned access by using memcpy() */ - memcpy(_stp_data_entry_data(entry), &t, sizeof(t)); - _stp_data_write_commit(entry); - } - else { - atomic_inc(&_stp_transport_failures); - return; - } - - while (len > 0) { - bytes_reserved = _stp_data_write_reserve(len, &entry); - if (likely(entry && bytes_reserved > 0)) { - memcpy(_stp_data_entry_data(entry), bufp, - bytes_reserved); - _stp_data_write_commit(entry); - bufp += bytes_reserved; - len -= bytes_reserved; - } - else { - atomic_inc(&_stp_transport_failures); - break; - } - } - } -#endif /* !NO_PERCPU_HEADERS */ - -#else /* !STP_BULKMODE */ - -#if STP_TRANSPORT_VERSION == 1 - - if (unlikely(_stp_ctl_write(STP_REALTIME_DATA, pb->buf, len) <= 0)) - atomic_inc (&_stp_transport_failures); - -#else /* STP_TRANSPORT_VERSION != 1 */ - { - unsigned long flags; - char *bufp = pb->buf; - - dbug_trans(1, "calling _stp_data_write...\n"); - spin_lock_irqsave(&_stp_print_lock, flags); - while (len > 0) { - size_t bytes_reserved; - - bytes_reserved = _stp_data_write_reserve(len, &entry); - if (likely(entry && bytes_reserved > 0)) { - memcpy(_stp_data_entry_data(entry), bufp, - bytes_reserved); - _stp_data_write_commit(entry); - bufp += bytes_reserved; - len -= bytes_reserved; - } - else { - atomic_inc(&_stp_transport_failures); - break; - } - } - spin_unlock_irqrestore(&_stp_print_lock, flags); - } -#endif /* STP_TRANSPORT_VERSION != 1 */ -#endif /* !STP_BULKMODE */ -} diff --git a/runtime/print_old.c b/runtime/print_old.c deleted file mode 100644 index 5c117e5f..00000000 --- a/runtime/print_old.c +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- linux-c -*- - * Print Flush Function - * Copyright (C) 2007 Red Hat Inc. - * - * This file is part of systemtap, and is free software. You can - * redistribute it and/or modify it under the terms of the GNU General - * Public License (GPL); either version 2, or (at your option) any - * later version. - */ - -/** Send the print buffer to the transport now. - * Output accumulates in the print buffer until it - * is filled, or this is called. This MUST be called before returning - * from a probe or accumulated output in the print buffer will be lost. - * - * @note Preemption must be disabled to use this. - */ - -void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb) -{ - uint32_t len = pb->len; - - /* check to see if there is anything in the buffer */ - if (likely (len == 0)) - return; - - pb->len = 0; - -#ifdef STP_BULKMODE - { -#ifdef NO_PERCPU_HEADERS - void *buf = relay_reserve(_stp_utt->rchan, len); - if (likely(buf)) - memcpy(buf, pb->buf, len); - else - atomic_inc (&_stp_transport_failures); -#else - void *buf = relay_reserve(_stp_utt->rchan, - sizeof(struct _stp_trace) + len); - if (likely(buf)) { - struct _stp_trace t = { .sequence = _stp_seq_inc(), - .pdu_len = len}; - memcpy(buf, &t, sizeof(t)); // prevent unaligned access - memcpy(buf + sizeof(t), pb->buf, len); - } else - atomic_inc (&_stp_transport_failures); -#endif - } -#else - { - if (unlikely(_stp_ctl_write(STP_REALTIME_DATA, pb->buf, len) <= 0)) - atomic_inc (&_stp_transport_failures); - } -#endif /* STP_BULKMODE */ -} -- cgit From eeb77fbbbd6494ec8b4496cb4e12104cb1c0e4e2 Mon Sep 17 00:00:00 2001 From: Przemyslaw Pawelczyk Date: Fri, 19 Jun 2009 00:27:45 +0200 Subject: Fix target_set tapset. Revise acquiring of pid and ppid in fork.return probe -- use returnval() and pid() instead of pid() and ppid() respectively. Add pid removal on exit syscall. Use dwarfless syscall probe aliases. Correct formatting. Signed-off-by: Josh Stone --- tapset/target_set.stp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/tapset/target_set.stp b/tapset/target_set.stp index c7878c52..9a4beced 100644 --- a/tapset/target_set.stp +++ b/tapset/target_set.stp @@ -3,25 +3,33 @@ global _target_set # map: target-set-pid -> ancestor-pid function target_set_pid (pid) { - return ([pid] in _target_set) + return ([pid] in _target_set) } probe begin { - if (target()) _target_set [target()] = stp_pid() + if (target()) + _target_set[target()] = stp_pid() } -probe syscall.fork.return +probe nd_syscall.fork.return { - pid=pid() - if (pid in _target_set) next - ppid=ppid() - if (ppid in _target_set) _target_set[pid]=ppid + pid = returnval() + if (pid in _target_set) + next + ppid = pid() + if (ppid in _target_set) + _target_set[pid] = ppid +} + +probe nd_syscall.exit +{ + delete _target_set[pid()] } function target_set_report () { - printf("target set:\n") - foreach (pid in _target_set+) - printf("%d begat %d\n", _target_set[pid], pid) + printf("target set:\n") + foreach (pid in _target_set+) + printf("%d begat %d\n", _target_set[pid], pid) } -- cgit From e6b653c8c2e63d54a3b33036130a6d8272680f54 Mon Sep 17 00:00:00 2001 From: William Cohen Date: Fri, 19 Jun 2009 11:33:29 -0400 Subject: Add froktracker.stp example. --- testsuite/systemtap.examples/index.html | 3 +++ testsuite/systemtap.examples/index.txt | 8 ++++++++ testsuite/systemtap.examples/keyword-index.html | 6 ++++++ testsuite/systemtap.examples/keyword-index.txt | 16 +++++++++++++++ .../systemtap.examples/process/forktracker.meta | 13 ++++++++++++ .../systemtap.examples/process/forktracker.stp | 23 ++++++++++++++++++++++ 6 files changed, 69 insertions(+) create mode 100644 testsuite/systemtap.examples/process/forktracker.meta create mode 100644 testsuite/systemtap.examples/process/forktracker.stp diff --git a/testsuite/systemtap.examples/index.html b/testsuite/systemtap.examples/index.html index a5fddb4e..c485713c 100644 --- a/testsuite/systemtap.examples/index.html +++ b/testsuite/systemtap.examples/index.html @@ -112,6 +112,9 @@ keywords: NETWORK process/errsnoop.stp - tabulate system call errors
        keywords: PROCESS SYSCALL

        The script prints a periodic tabular report about failing system calls, by process and by syscall failure. The first optional argument specifies the reporting interval (in seconds, default 5); the second optional argument gives a screen height (number of lines in the report, default 20).

        +
      • process/forktracker.stp - Trace Creation of Processes
        +keywords: PROCESS SCHEDULER
        +

        The forktracker.stp script prints out a time-stamped entry showing each fork and exec operation on the machine. This can be useful for determine what process is creating a flurry of short-lived processes.

      • process/futexes.stp - System-Wide Futex Contention
        keywords: SYSCALL LOCKING FUTEX

        The script watches the futex syscall on the system. On exit the futexes address, the number of contentions, and the average time for each contention on the futex are printed from lowest pid number to highest.

      • diff --git a/testsuite/systemtap.examples/index.txt b/testsuite/systemtap.examples/index.txt index 95e81435..caf1a5ff 100644 --- a/testsuite/systemtap.examples/index.txt +++ b/testsuite/systemtap.examples/index.txt @@ -224,6 +224,14 @@ keywords: process syscall in the report, default 20). +process/forktracker.stp - Trace Creation of Processes +keywords: process scheduler + + The forktracker.stp script prints out a time-stamped entry showing + each fork and exec operation on the machine. This can be useful for + determine what process is creating a flurry of short-lived processes. + + process/futexes.stp - System-Wide Futex Contention keywords: syscall locking futex diff --git a/testsuite/systemtap.examples/keyword-index.html b/testsuite/systemtap.examples/keyword-index.html index e144337c..9852c992 100644 --- a/testsuite/systemtap.examples/keyword-index.html +++ b/testsuite/systemtap.examples/keyword-index.html @@ -210,6 +210,9 @@ keywords: NETWORK process/errsnoop.stp - tabulate system call errors
        keywords: PROCESS SYSCALL

        The script prints a periodic tabular report about failing system calls, by process and by syscall failure. The first optional argument specifies the reporting interval (in seconds, default 5); the second optional argument gives a screen height (number of lines in the report, default 20).

        +
      • process/forktracker.stp - Trace Creation of Processes
        +keywords: PROCESS SCHEDULER
        +

        The forktracker.stp script prints out a time-stamped entry showing each fork and exec operation on the machine. This can be useful for determine what process is creating a flurry of short-lived processes.

      • process/schedtimes.stp - Track Time Processes Spend in Various States using Tracepoints
        keywords: PROCESS SCHEDULER TIME TRACEPOINT

        The schedtimes.stp script instruments the scheduler to track the amount of time that each process spends running, sleeping, queued, and waiting for io. On exit the script prints out the accumulated time for each state of processes observed. Optionally, this script can be used with the '-c' or '-x' options to focus on a specific PID.

      • @@ -243,6 +246,9 @@ keywords: SYSCALL SCHEDULER
          +
        • process/forktracker.stp - Trace Creation of Processes
          +keywords: PROCESS SCHEDULER
          +

          The forktracker.stp script prints out a time-stamped entry showing each fork and exec operation on the machine. This can be useful for determine what process is creating a flurry of short-lived processes.

        • process/schedtimes.stp - Track Time Processes Spend in Various States using Tracepoints
          keywords: PROCESS SCHEDULER TIME TRACEPOINT

          The schedtimes.stp script instruments the scheduler to track the amount of time that each process spends running, sleeping, queued, and waiting for io. On exit the script prints out the accumulated time for each state of processes observed. Optionally, this script can be used with the '-c' or '-x' options to focus on a specific PID.

        • diff --git a/testsuite/systemtap.examples/keyword-index.txt b/testsuite/systemtap.examples/keyword-index.txt index 8305e208..4778afc7 100644 --- a/testsuite/systemtap.examples/keyword-index.txt +++ b/testsuite/systemtap.examples/keyword-index.txt @@ -390,6 +390,14 @@ keywords: process syscall in the report, default 20). +process/forktracker.stp - Trace Creation of Processes +keywords: process scheduler + + The forktracker.stp script prints out a time-stamped entry showing + each fork and exec operation on the machine. This can be useful for + determine what process is creating a flurry of short-lived processes. + + process/schedtimes.stp - Track Time Processes Spend in Various States using Tracepoints keywords: process scheduler time tracepoint @@ -480,6 +488,14 @@ keywords: syscall read write time io = SCHEDULER = +process/forktracker.stp - Trace Creation of Processes +keywords: process scheduler + + The forktracker.stp script prints out a time-stamped entry showing + each fork and exec operation on the machine. This can be useful for + determine what process is creating a flurry of short-lived processes. + + process/schedtimes.stp - Track Time Processes Spend in Various States using Tracepoints keywords: process scheduler time tracepoint diff --git a/testsuite/systemtap.examples/process/forktracker.meta b/testsuite/systemtap.examples/process/forktracker.meta new file mode 100644 index 00000000..f3ef3709 --- /dev/null +++ b/testsuite/systemtap.examples/process/forktracker.meta @@ -0,0 +1,13 @@ +title: Trace Creation of Processes +name: forktracker.stp +version: 0.1 +author: Phil Muldoon at Red Hat +keywords: process scheduler +subsystem: scheduler +status: production +exit: user-controlled +output: trace +scope: system-wide +description: The forktracker.stp script prints out a time-stamped entry showing each fork and exec operation on the machine. This can be useful for determine what process is creating a flurry of short-lived processes. +test_check: stap -p4 forktracker.stp +test_installcheck: stap forkracker.stp -c "sleep 1" diff --git a/testsuite/systemtap.examples/process/forktracker.stp b/testsuite/systemtap.examples/process/forktracker.stp new file mode 100644 index 00000000..525aa0a5 --- /dev/null +++ b/testsuite/systemtap.examples/process/forktracker.stp @@ -0,0 +1,23 @@ +#! /usr/bin/env stap +# +# This is a stap script to monitor process creations (fork(), exec()'s). +# Based off of stap script found: http://picobot.org/wordpress/?p=27 +# With some minor modifications (i.e. timestamping) +# +# Usage: stap forktracker.stp +# +# Sample output: +# +# timestamp: process_name (pid) new_pid +# +# Version 0.1 + +probe kprocess.create { + printf("%-25s: %s (%d) created %d\n", + ctime(gettimeofday_s()), execname(), pid(), new_pid) +} + +probe kprocess.exec { + printf("%-25s: %s (%d) is exec'ing %s\n", + ctime(gettimeofday_s()), execname(), pid(), filename) +} -- cgit From 0c98234c86877cfea3df762dc8627b3f05c38e75 Mon Sep 17 00:00:00 2001 From: William Cohen Date: Fri, 19 Jun 2009 11:38:28 -0400 Subject: Make examples-index-gen.pl executable. --- testsuite/systemtap.examples/examples-index-gen.pl | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 testsuite/systemtap.examples/examples-index-gen.pl diff --git a/testsuite/systemtap.examples/examples-index-gen.pl b/testsuite/systemtap.examples/examples-index-gen.pl old mode 100644 new mode 100755 -- cgit From e94030f6ab5c9022e69c3b362d9fe3639718f06d Mon Sep 17 00:00:00 2001 From: William Cohen Date: Fri, 19 Jun 2009 11:47:53 -0400 Subject: Make forktracker.stp example executable. --- testsuite/systemtap.examples/process/forktracker.stp | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 testsuite/systemtap.examples/process/forktracker.stp diff --git a/testsuite/systemtap.examples/process/forktracker.stp b/testsuite/systemtap.examples/process/forktracker.stp old mode 100644 new mode 100755 -- cgit From 92b1a0c0ead841e781783e8f94cf22fa4694fc35 Mon Sep 17 00:00:00 2001 From: William Cohen Date: Fri, 19 Jun 2009 12:07:19 -0400 Subject: Revert "Make examples-index-gen.pl executable." This reverts commit 0c98234c86877cfea3df762dc8627b3f05c38e75. --- testsuite/systemtap.examples/examples-index-gen.pl | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 testsuite/systemtap.examples/examples-index-gen.pl diff --git a/testsuite/systemtap.examples/examples-index-gen.pl b/testsuite/systemtap.examples/examples-index-gen.pl old mode 100755 new mode 100644 -- cgit From 3aae22ce894f935ac1371f501a09cecfbde18727 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 19 Jun 2009 11:13:15 -0500 Subject: Disabled transport version 3 (for now). --- runtime/transport/transport.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 7f844f5d..1d029e53 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -31,6 +31,12 @@ static int _stp_ctl_attached = 0; static pid_t _stp_target = 0; static int _stp_probes_started = 0; +// For now, disable transport version 3 +#if STP_TRANSPORT_VERSION == 3 +#undef STP_TRANSPORT_VERSION +#define STP_TRANSPORT_VERSION 2 +#endif + #include "control.h" #if STP_TRANSPORT_VERSION == 1 #include "relayfs.c" -- cgit From 45148f5b5e371ff852dbbb08d83c5e87932b372e Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Fri, 19 Jun 2009 14:04:55 -0400 Subject: Rename static_uprobes.exp to sdt_misc.exp --- testsuite/systemtap.base/sdt_misc.exp | 232 ++++++++++++++++++++++++++++ testsuite/systemtap.base/static_uprobes.exp | 232 ---------------------------- 2 files changed, 232 insertions(+), 232 deletions(-) create mode 100644 testsuite/systemtap.base/sdt_misc.exp delete mode 100644 testsuite/systemtap.base/static_uprobes.exp diff --git a/testsuite/systemtap.base/sdt_misc.exp b/testsuite/systemtap.base/sdt_misc.exp new file mode 100644 index 00000000..6a597646 --- /dev/null +++ b/testsuite/systemtap.base/sdt_misc.exp @@ -0,0 +1,232 @@ +set test "static_user_markers" + +# Test miscellaneous features of .mark probes + +# Compile a C program to use as the user-space probing target +set sup_srcpath "[pwd]/static_user_markers.c" +set sup_exepath "[pwd]/static_user_markers.x" +set supcplus_exepath "[pwd]/static_user_markers_cplus.x" +set fp [open $sup_srcpath "w"] +puts $fp " +#include +#define USE_STAP_PROBE 1 +#include \"static_user_markers_.h\" + +void +bar (int i) +{ + STATIC_USER_MARKERS_TEST_PROBE_2(i); + if (i == 0) + i = 1000; + STAP_PROBE1(static_uprobes,test_probe_2,i); +} + +void +baz (int i, char* s) +{ + STAP_PROBE1(static_uprobes,test_probe_0,i); + if (i == 0) + i = 1000; + STATIC_USER_MARKERS_TEST_PROBE_3(i,s); +} + +void +buz (int parm) +{ + if (parm == 0) + parm = 1000; + DTRACE_PROBE1(static_user_markers,test_probe_4,parm); +} + +int +main () +{ + bar(2); + baz(3,(char*)\"abc\"); + buz(4); +} +" +close $fp + +set sup_stppath "[pwd]/static_user_markers.stp" +set fp [open $sup_stppath "w"] +puts $fp " +probe process(\"static_user_markers.x\").mark(\"test_probe_0\") +{ + printf(\"In test_probe_0 probe %#x\\n\", \$arg1) +} +probe process(\"static_user_markers.x\").mark(\"test_probe_2\") +{ + printf(\"In test_probe_2 probe %#x\\n\", \$arg1) +} +probe process(\"static_user_markers.x\").mark(\"test_probe_3\") +{ + printf(\"In test_probe_3 probe %#x %#x\\n\", \$arg1, \$arg2) +} +probe process(\"static_user_markers.x\").mark(\"test_probe_4\") +{ + printf(\"In test_probe_4 dtrace probe %#x\\n\", \$arg1) +} +" +close $fp + +set sup_dpath "[pwd]/static_user_markers_.d" +set sup_hpath "[pwd]/static_user_markers_.h" +set fp [open $sup_dpath "w"] +puts $fp " +provider static_user_markers { + probe test_probe_1 (); + probe test_probe_2 (int i); + probe test_probe_3 (int i, char* x); + probe test_probe_4 (int i); +}; +" +close $fp + +# Test dtrace + +if {[installtest_p]} { + set dtrace $env(SYSTEMTAP_PATH)/dtrace +} else { + set dtrace $srcdir/../dtrace +} +if {[catch {exec $dtrace -h -s $sup_dpath} res]} { + verbose -log "unable to run $dtrace: $res" +} +if {[file exists $sup_hpath]} then { + pass "$test dtrace" +} else { + fail "$test dtrace" + if { $verbose == 0 } { + catch {exec rm -f $sup_srcpath $sup_hpath $sup_stppath} + } + return +} + +if {[installtest_p]} { + set sdtdir $env(SYSTEMTAP_INCLUDES) +} else { + set sdtdir $srcdir/../includes +} + +set pbtype_flags {{""} {additional_flags=-DEXPERIMENTAL_UTRACE_SDT} {additional_flags=-DEXPERIMENTAL_KPROBE_SDT}} +set pbtype_mssgs {{uprobe} {utrace} {kprobe}} + +# Iterate pbtype_flags +for {set i 0} {$i < [llength $pbtype_flags]} {incr i} { +set pbtype_flag [lindex $pbtype_flags $i] +set pbtype_mssg [lindex $pbtype_mssgs $i] +set testprog "sdt.c.exe.$i" + +set sup_flags "additional_flags=-I$srcdir/../includes/sys" +set sup_flags "$sup_flags additional_flags=-I$sdtdir" +set sup_flags "$sup_flags additional_flags=-g" +set sup_flags "$sup_flags additional_flags=-O" +set sup_flags "$sup_flags additional_flags=-I. $pbtype_flag" +set res [target_compile $sup_srcpath $sup_exepath executable $sup_flags] +if { $res != "" } { + verbose "target_compile failed: $res" 2 + fail "$test compiling -g $pbtype_mssg" + if { $verbose == 0 } { + catch {exec rm -f $sup_srcpath $sup_hpath $sup_stppath} + } + return +} else { + pass "$test compiling -g $pbtype_mssg" +} + +if {![installtest_p]} {untested $test; return} +if {![utrace_p]} { + untested "$test" + if { $verbose == 0 } { + catch {exec rm -f $sup_srcpath} + } + return +} + +# Run stap on executable built with dtrace generated header file + +set ok 0 + +verbose -log "spawn stap -c $sup_exepath $sup_stppath" +spawn stap -c $sup_exepath $sup_stppath +expect { + -timeout 180 + -re {In test_probe_2 probe 0x2} { incr ok; exp_continue } + -re {In test_probe_0 probe 0x3} { incr ok; exp_continue } + -re {In test_probe_3 probe 0x3 0x[0-9a-f][0-9a-f]} { incr ok; exp_continue } + -re {In test_probe_4 dtrace probe 0x4} { incr ok; exp_continue } + timeout { fail "$test (timeout)" } + eof { } +} + +wait + +if {$ok == 5} { + pass "$test $pbtype_mssg" +} else { + fail "$test ($ok) $pbtype_mssg" +} + +# Test passing various C types to .mark probes + +set sup_flags "$sup_flags additional_flags=-O0 $pbtype_flag" +set res [target_compile $srcdir/$subdir/sdt_types.c sdt_types.x executable $sup_flags] +if { $res != "" } { + verbose "target_compile failed: $res" 2 + fail "$test compiling types -g $pbtype_mssg" + return +} else { + pass "$test compiling types -g $pbtype_mssg" +} + +set ok 0 +set fail "types" +verbose -log "spawn stap -c ./sdt_types.x $srcdir/$subdir/sdt_types.stp ./sdt_types.x" +spawn stap -c ./sdt_types.x $srcdir/$subdir/sdt_types.stp ./sdt_types.x +expect { + -timeout 180 + -re {FAIL: [a-z_]+var} { regexp " .*$" $expect_out(0,string) s; + incr ok; set fail "$fail $s"; exp_continue } + timeout { fail "$test (timeout) } + eof { } +} + +wait + +set pbtype_mssgs {{uprobe} {utrace} {kprobe}} +if { $ok != 0} { + if { $pbtype_mssg == "uprobe" } { + fail "$test $fail $pbtype_mssg" + } else { + # (needs cast) + xfail "$test $fail $pbtype_mssg" + } +} else { + pass "$test types $pbtype_mssg" +} + +# Test .mark probe wildcard matching + +set ok 0 +spawn stap -l "process(\"./sdt_types.x\").mark(\"*\")" +expect { + -timeout 180 + -re {mark\(\"[a-z_]+\"\)} { incr ok; exp_continue } + timeout { fail "$test (timeout)" } + eof { } +} + +if { $ok == 45 } { + pass "$test wildcard $pbtype_mssg" +} else { + fail "$test wildcard ($ok) $pbtype_mssg" +} + +# for {set i 0} +} + +if { $verbose == 0 } { +catch {exec rm -f $sup_srcpath $sup_exepath $supcplus_exepath $sup_dpath $sup_hpath $sup_stppath sdt_types.x} +} + diff --git a/testsuite/systemtap.base/static_uprobes.exp b/testsuite/systemtap.base/static_uprobes.exp deleted file mode 100644 index 6a597646..00000000 --- a/testsuite/systemtap.base/static_uprobes.exp +++ /dev/null @@ -1,232 +0,0 @@ -set test "static_user_markers" - -# Test miscellaneous features of .mark probes - -# Compile a C program to use as the user-space probing target -set sup_srcpath "[pwd]/static_user_markers.c" -set sup_exepath "[pwd]/static_user_markers.x" -set supcplus_exepath "[pwd]/static_user_markers_cplus.x" -set fp [open $sup_srcpath "w"] -puts $fp " -#include -#define USE_STAP_PROBE 1 -#include \"static_user_markers_.h\" - -void -bar (int i) -{ - STATIC_USER_MARKERS_TEST_PROBE_2(i); - if (i == 0) - i = 1000; - STAP_PROBE1(static_uprobes,test_probe_2,i); -} - -void -baz (int i, char* s) -{ - STAP_PROBE1(static_uprobes,test_probe_0,i); - if (i == 0) - i = 1000; - STATIC_USER_MARKERS_TEST_PROBE_3(i,s); -} - -void -buz (int parm) -{ - if (parm == 0) - parm = 1000; - DTRACE_PROBE1(static_user_markers,test_probe_4,parm); -} - -int -main () -{ - bar(2); - baz(3,(char*)\"abc\"); - buz(4); -} -" -close $fp - -set sup_stppath "[pwd]/static_user_markers.stp" -set fp [open $sup_stppath "w"] -puts $fp " -probe process(\"static_user_markers.x\").mark(\"test_probe_0\") -{ - printf(\"In test_probe_0 probe %#x\\n\", \$arg1) -} -probe process(\"static_user_markers.x\").mark(\"test_probe_2\") -{ - printf(\"In test_probe_2 probe %#x\\n\", \$arg1) -} -probe process(\"static_user_markers.x\").mark(\"test_probe_3\") -{ - printf(\"In test_probe_3 probe %#x %#x\\n\", \$arg1, \$arg2) -} -probe process(\"static_user_markers.x\").mark(\"test_probe_4\") -{ - printf(\"In test_probe_4 dtrace probe %#x\\n\", \$arg1) -} -" -close $fp - -set sup_dpath "[pwd]/static_user_markers_.d" -set sup_hpath "[pwd]/static_user_markers_.h" -set fp [open $sup_dpath "w"] -puts $fp " -provider static_user_markers { - probe test_probe_1 (); - probe test_probe_2 (int i); - probe test_probe_3 (int i, char* x); - probe test_probe_4 (int i); -}; -" -close $fp - -# Test dtrace - -if {[installtest_p]} { - set dtrace $env(SYSTEMTAP_PATH)/dtrace -} else { - set dtrace $srcdir/../dtrace -} -if {[catch {exec $dtrace -h -s $sup_dpath} res]} { - verbose -log "unable to run $dtrace: $res" -} -if {[file exists $sup_hpath]} then { - pass "$test dtrace" -} else { - fail "$test dtrace" - if { $verbose == 0 } { - catch {exec rm -f $sup_srcpath $sup_hpath $sup_stppath} - } - return -} - -if {[installtest_p]} { - set sdtdir $env(SYSTEMTAP_INCLUDES) -} else { - set sdtdir $srcdir/../includes -} - -set pbtype_flags {{""} {additional_flags=-DEXPERIMENTAL_UTRACE_SDT} {additional_flags=-DEXPERIMENTAL_KPROBE_SDT}} -set pbtype_mssgs {{uprobe} {utrace} {kprobe}} - -# Iterate pbtype_flags -for {set i 0} {$i < [llength $pbtype_flags]} {incr i} { -set pbtype_flag [lindex $pbtype_flags $i] -set pbtype_mssg [lindex $pbtype_mssgs $i] -set testprog "sdt.c.exe.$i" - -set sup_flags "additional_flags=-I$srcdir/../includes/sys" -set sup_flags "$sup_flags additional_flags=-I$sdtdir" -set sup_flags "$sup_flags additional_flags=-g" -set sup_flags "$sup_flags additional_flags=-O" -set sup_flags "$sup_flags additional_flags=-I. $pbtype_flag" -set res [target_compile $sup_srcpath $sup_exepath executable $sup_flags] -if { $res != "" } { - verbose "target_compile failed: $res" 2 - fail "$test compiling -g $pbtype_mssg" - if { $verbose == 0 } { - catch {exec rm -f $sup_srcpath $sup_hpath $sup_stppath} - } - return -} else { - pass "$test compiling -g $pbtype_mssg" -} - -if {![installtest_p]} {untested $test; return} -if {![utrace_p]} { - untested "$test" - if { $verbose == 0 } { - catch {exec rm -f $sup_srcpath} - } - return -} - -# Run stap on executable built with dtrace generated header file - -set ok 0 - -verbose -log "spawn stap -c $sup_exepath $sup_stppath" -spawn stap -c $sup_exepath $sup_stppath -expect { - -timeout 180 - -re {In test_probe_2 probe 0x2} { incr ok; exp_continue } - -re {In test_probe_0 probe 0x3} { incr ok; exp_continue } - -re {In test_probe_3 probe 0x3 0x[0-9a-f][0-9a-f]} { incr ok; exp_continue } - -re {In test_probe_4 dtrace probe 0x4} { incr ok; exp_continue } - timeout { fail "$test (timeout)" } - eof { } -} - -wait - -if {$ok == 5} { - pass "$test $pbtype_mssg" -} else { - fail "$test ($ok) $pbtype_mssg" -} - -# Test passing various C types to .mark probes - -set sup_flags "$sup_flags additional_flags=-O0 $pbtype_flag" -set res [target_compile $srcdir/$subdir/sdt_types.c sdt_types.x executable $sup_flags] -if { $res != "" } { - verbose "target_compile failed: $res" 2 - fail "$test compiling types -g $pbtype_mssg" - return -} else { - pass "$test compiling types -g $pbtype_mssg" -} - -set ok 0 -set fail "types" -verbose -log "spawn stap -c ./sdt_types.x $srcdir/$subdir/sdt_types.stp ./sdt_types.x" -spawn stap -c ./sdt_types.x $srcdir/$subdir/sdt_types.stp ./sdt_types.x -expect { - -timeout 180 - -re {FAIL: [a-z_]+var} { regexp " .*$" $expect_out(0,string) s; - incr ok; set fail "$fail $s"; exp_continue } - timeout { fail "$test (timeout) } - eof { } -} - -wait - -set pbtype_mssgs {{uprobe} {utrace} {kprobe}} -if { $ok != 0} { - if { $pbtype_mssg == "uprobe" } { - fail "$test $fail $pbtype_mssg" - } else { - # (needs cast) - xfail "$test $fail $pbtype_mssg" - } -} else { - pass "$test types $pbtype_mssg" -} - -# Test .mark probe wildcard matching - -set ok 0 -spawn stap -l "process(\"./sdt_types.x\").mark(\"*\")" -expect { - -timeout 180 - -re {mark\(\"[a-z_]+\"\)} { incr ok; exp_continue } - timeout { fail "$test (timeout)" } - eof { } -} - -if { $ok == 45 } { - pass "$test wildcard $pbtype_mssg" -} else { - fail "$test wildcard ($ok) $pbtype_mssg" -} - -# for {set i 0} -} - -if { $verbose == 0 } { -catch {exec rm -f $sup_srcpath $sup_exepath $supcplus_exepath $sup_dpath $sup_hpath $sup_stppath sdt_types.x} -} - -- cgit -- cgit From 54bc8f42438e7efc62c5dd2b39618ccd6c953cdd Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Fri, 19 Jun 2009 16:13:21 -0400 Subject: Correctly find probes for -m32 executables. * sdt.h (STAP_PROBE_DATA_): Pad with 0 so final probe entry doesn't pickup a stray word. * sdt_misc.exp (static_user_markers.{c,d}): Add bstruct to test struct type handling --- includes/sys/sdt.h | 1 + testsuite/systemtap.base/sdt_misc.exp | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/includes/sys/sdt.h b/includes/sys/sdt.h index 0f86cc3b..07ece7c1 100644 --- a/includes/sys/sdt.h +++ b/includes/sys/sdt.h @@ -32,6 +32,7 @@ STAP_PROBE_ADDR "1b\n" \ "\t.align 8\n" \ STAP_PROBE_ADDR #arg "\n" \ + "\t.int 0\n" \ "\t.previous\n") #define STAP_PROBE_DATA(probe, guard, arg) \ diff --git a/testsuite/systemtap.base/sdt_misc.exp b/testsuite/systemtap.base/sdt_misc.exp index 6a597646..459b669a 100644 --- a/testsuite/systemtap.base/sdt_misc.exp +++ b/testsuite/systemtap.base/sdt_misc.exp @@ -33,9 +33,15 @@ baz (int i, char* s) void buz (int parm) { + struct astruct + { + int a; + int b; + }; + struct astruct bstruct = {parm, parm + 1}; if (parm == 0) parm = 1000; - DTRACE_PROBE1(static_user_markers,test_probe_4,parm); + DTRACE_PROBE1(static_user_markers,test_probe_4,&bstruct); } int @@ -65,21 +71,23 @@ probe process(\"static_user_markers.x\").mark(\"test_probe_3\") } probe process(\"static_user_markers.x\").mark(\"test_probe_4\") { - printf(\"In test_probe_4 dtrace probe %#x\\n\", \$arg1) + printf(\"In test_probe_4 dtrace probe %#x %#x\\n\", \$arg1->a, \$arg1->b) } " close $fp set sup_dpath "[pwd]/static_user_markers_.d" set sup_hpath "[pwd]/static_user_markers_.h" +set sup_opath "[pwd]/static_user_markers_.o" set fp [open $sup_dpath "w"] puts $fp " provider static_user_markers { probe test_probe_1 (); probe test_probe_2 (int i); probe test_probe_3 (int i, char* x); - probe test_probe_4 (int i); + probe test_probe_4 (struct astruct arg); }; +struct astruct {int a; int b;}; " close $fp @@ -90,10 +98,10 @@ if {[installtest_p]} { } else { set dtrace $srcdir/../dtrace } -if {[catch {exec $dtrace -h -s $sup_dpath} res]} { +if {[catch {exec $dtrace --types -G -s $sup_dpath} res]} { verbose -log "unable to run $dtrace: $res" } -if {[file exists $sup_hpath]} then { +if {[file exists $sup_hpath] && [file exists $sup_opath]} then { pass "$test dtrace" } else { fail "$test dtrace" @@ -109,7 +117,7 @@ if {[installtest_p]} { set sdtdir $srcdir/../includes } -set pbtype_flags {{""} {additional_flags=-DEXPERIMENTAL_UTRACE_SDT} {additional_flags=-DEXPERIMENTAL_KPROBE_SDT}} +set pbtype_flags {{""} {additional_flags=-O additional_flags=-DEXPERIMENTAL_UTRACE_SDT} {additional_flags=-O additional_flags=-DEXPERIMENTAL_KPROBE_SDT}} set pbtype_mssgs {{uprobe} {utrace} {kprobe}} # Iterate pbtype_flags @@ -121,8 +129,8 @@ set testprog "sdt.c.exe.$i" set sup_flags "additional_flags=-I$srcdir/../includes/sys" set sup_flags "$sup_flags additional_flags=-I$sdtdir" set sup_flags "$sup_flags additional_flags=-g" -set sup_flags "$sup_flags additional_flags=-O" -set sup_flags "$sup_flags additional_flags=-I. $pbtype_flag" +set sup_flags "$sup_flags additional_flags=$sup_opath" +set sup_flags "$sup_flags additional_flags=-I. $pbtype_flag" set res [target_compile $sup_srcpath $sup_exepath executable $sup_flags] if { $res != "" } { verbose "target_compile failed: $res" 2 @@ -155,7 +163,7 @@ expect { -re {In test_probe_2 probe 0x2} { incr ok; exp_continue } -re {In test_probe_0 probe 0x3} { incr ok; exp_continue } -re {In test_probe_3 probe 0x3 0x[0-9a-f][0-9a-f]} { incr ok; exp_continue } - -re {In test_probe_4 dtrace probe 0x4} { incr ok; exp_continue } + -re {In test_probe_4 dtrace probe 0x4 0x5} { incr ok; exp_continue } timeout { fail "$test (timeout)" } eof { } } @@ -170,7 +178,7 @@ if {$ok == 5} { # Test passing various C types to .mark probes -set sup_flags "$sup_flags additional_flags=-O0 $pbtype_flag" +set sup_flags "$sup_flags $pbtype_flag additional_flags=-O0 " set res [target_compile $srcdir/$subdir/sdt_types.c sdt_types.x executable $sup_flags] if { $res != "" } { verbose "target_compile failed: $res" 2 -- cgit From d3584129c20e4246ed5fe53b0f14105d8b7fa212 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 19 Jun 2009 18:19:51 -0400 Subject: Fix on-file flight recorder mode bugs on old kernel. * runtime/staprun/common.c (make_outfile_name): Moved from relay.c, fix not to open /dev/null.XXX output files, and add 'bulk' argument for bulkmode. * runtime/staprun/relay.c (make_outfile_name): Moved to common.c. * runtime/staprun/relay_old.c (open_oldoutfile): Fix to use fopen() and store FILE * to percpu_tmpfile[cpu]. --- runtime/staprun/common.c | 27 +++++++++++++++++++++++++++ runtime/staprun/relay.c | 30 +++--------------------------- runtime/staprun/relay_old.c | 17 ++++++++++------- runtime/staprun/staprun.h | 3 ++- 4 files changed, 42 insertions(+), 35 deletions(-) diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c index c67ce340..5c4a8431 100644 --- a/runtime/staprun/common.c +++ b/runtime/staprun/common.c @@ -66,6 +66,33 @@ int stap_strfloctime(char *buf, size_t max, const char *fmt, time_t t) return (int)ret; } +int make_outfile_name(char *buf, int max, int fnum, int cpu, time_t t, int bulk) +{ + int len; + if (PATH_MAX < max) + max = PATH_MAX; + len = stap_strfloctime(buf, max, outfile_name, t); + if (len < 0) { + err("Invalid FILE name format\n"); + return -1; + } + /* special case: for testing we sometimes want to write to /dev/null */ + if (strcmp(outfile_name, "/dev/null") == 0) { + strcpy(buf, "/dev/null"); + } else { + if (bulk) { + if (snprintf_chk(&buf[len], max - len, "_cpu%d.%d", + cpu, fnum)) + return -1; + } else { + /* stream mode */ + if (snprintf_chk(&buf[len], max - len, ".%d", fnum)) + return -1; + } + } + return 0; +} + void parse_args(int argc, char **argv) { int c; diff --git a/runtime/staprun/relay.c b/runtime/staprun/relay.c index b9796241..f4aa139f 100644 --- a/runtime/staprun/relay.c +++ b/runtime/staprun/relay.c @@ -73,31 +73,6 @@ time_t read_backlog(int cpu, int fnum) return time_backlog[cpu][fnum & BACKLOG_MASK]; } -int make_outfile_name(char *buf, int max, int fnum, int cpu, time_t t) -{ - int len; - len = stap_strfloctime(buf, max, outfile_name, t); - if (len < 0) { - err("Invalid FILE name format\n"); - return -1; - } - if (bulkmode) { - /* special case: for testing we sometimes want to write to /dev/null */ - if (strcmp(outfile_name, "/dev/null") == 0) { - strcpy(buf, "/dev/null"); - } else { - if (snprintf_chk(&buf[len], PATH_MAX - len, - "_cpu%d.%d", cpu, fnum)) - return -1; - } - } else { - /* stream mode */ - if (snprintf_chk(&buf[len], PATH_MAX - len, ".%d", fnum)) - return -1; - } - return 0; -} - static int open_outfile(int fnum, int cpu, int remove_file) { char buf[PATH_MAX]; @@ -112,14 +87,15 @@ static int open_outfile(int fnum, int cpu, int remove_file) if (remove_file) { /* remove oldest file */ if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max, - cpu, read_backlog(cpu, fnum - fnum_max)) < 0) + cpu, read_backlog(cpu, fnum - fnum_max), + bulkmode) < 0) return -1; remove(buf); /* don't care */ } write_backlog(cpu, fnum, t); } - if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t) < 0) + if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t, bulkmode) < 0) return -1; out_fd[cpu] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666); if (out_fd[cpu] < 0) { diff --git a/runtime/staprun/relay_old.c b/runtime/staprun/relay_old.c index 33d2daf3..71d8acee 100644 --- a/runtime/staprun/relay_old.c +++ b/runtime/staprun/relay_old.c @@ -87,30 +87,33 @@ static int open_oldoutfile(int fnum, int cpu, int remove_file) if (fnum_max) { if (remove_file) { /* remove oldest file */ - if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max, - cpu, read_backlog(cpu, fnum - fnum_max)) < 0) + if (make_outfile_name(buf, PATH_MAX, + fnum - fnum_max, cpu, + read_backlog(cpu, fnum - fnum_max), + bulkmode) < 0) return -1; remove(buf); /* don't care */ } write_backlog(cpu, fnum, t); } - if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t) < 0) + if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t, bulkmode) < 0) return -1; } else if (bulkmode) { if (sprintf_chk(buf, "stpd_cpu%d.%d", cpu, fnum)) return -1; } else { /* stream mode */ - out_fd[cpu] = STDOUT_FILENO; + percpu_tmpfile[cpu] = stdout; return 0; } - out_fd[cpu] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666); - if (out_fd[cpu] < 0) { + if((percpu_tmpfile[cpu] = fopen(buf, "w+")) == NULL) { perr("Couldn't open output file %s", buf); return -1; } - if (set_clexec(out_fd[cpu]) < 0) + if (set_clexec(fileno(percpu_tmpfile[cpu])) < 0) { + perr("Couldn't clear exec bit of open output file %s", buf); return -1; + } return 0; } /** diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index bd6402e4..3c9dab3f 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -120,7 +120,8 @@ int init_oldrelayfs(void); void close_oldrelayfs(int); int write_realtime_data(void *data, ssize_t nb); void setup_signals(void); -int make_outfile_name(char *buf, int max, int fnum, int cpu, time_t t); +int make_outfile_name(char *buf, int max, int fnum, int cpu, + time_t t, int bulk); int init_backlog(int cpu); void write_backlog(int cpu, int fnum, time_t t); time_t read_backlog(int cpu, int fnum); -- cgit From 98a1242d112575a8e65258f17611dd01c84fc45b Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 19 Jun 2009 18:19:52 -0400 Subject: Fix various issues in initscript (bz506956) * initscript/systemtap.in: Fix messages. (clog): Don't strip spaces out. (parse_args): Parse -y option. (status): Show message if no scripts are running. (restart): Don't try to stop scripts if no scripts are running. --- initscript/systemtap.in | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/initscript/systemtap.in b/initscript/systemtap.in index 918455d6..7552df44 100644 --- a/initscript/systemtap.in +++ b/initscript/systemtap.in @@ -74,7 +74,7 @@ log () { # message echo `LC_ALL=en date +"%b %e %T"`": $1" >> "$LOG_FILE" } clog () { # message [-n] - echo $2 $1 + echo $2 "$1" log "$1" } slog () { # message @@ -154,7 +154,7 @@ parse_args () { # arguments CMD=$1 shift 1 -OPTS=`getopt -s bash -u -o 'r:c:R' -- $@` +OPTS=`getopt -s bash -u -o 'r:c:Ry' -- $@` if [ $? -ne 0 ]; then slog "Error: Argument parse error: $@" failure $"parse error" @@ -381,7 +381,7 @@ compile_script () { # script checkcache clog " Compiling $1 ... " -n tmpdir=`mktemp -d -p "$TEMP_PATH" cache.XXXXXXXX` if [ $? -ne 0 ]; then - clog "failed to create temporary directory." + clog "Failed to create temporary directory." return 1 fi pushd "$tmpdir" &> /dev/null @@ -460,7 +460,7 @@ start_script () { # script clog " Starting $1 ... " -n tmpdir=`mktemp -d -p "$TEMP_PATH" cache.XXXXXXXX` # bz7097 if [ $? -ne 0 ]; then - clog "failed to create temporary directory." + clog "Failed to create temporary directory." return 1 fi pushd "$tmpdir" &> /dev/null @@ -486,7 +486,7 @@ start () { fi if [ -z "$SCRIPTS" ]; then - do_warning $"no scripts exist." + do_warning $"No scripts exist." return 5 # program is not installed fi @@ -553,7 +553,7 @@ stop () { done for s in $sl; do stop_script $s - [ $? -ne 0 ] && might_fail $"Failed to run \"$s\". " + [ $? -ne 0 ] && might_fail $"Failed to stop \"$s\". " done might_success $"$prog stopping " return 0 @@ -563,6 +563,10 @@ status () { local s pid ret r [ -z "$SCRIPTS" ] && SCRIPTS=`get_all_runnings` ret=3 + if [ -z "$SCRIPTS" ] ; then + echo "No systemtap scripts are present" + return $ret + fi for s in $SCRIPTS; do check_running $s r=$? @@ -581,7 +585,7 @@ status () { compile () { local s ss - clog $"Compiling $prog: " -n + clog $"Compiling systemtap scripts: " -n prepare_cache_dir if [ $? -ne 0 ]; then do_failure $"Failed to make cache directory ($CACHE_PATH)" @@ -607,7 +611,7 @@ compile () { # Cleanup caches cleanup () { local s ss ret - clog $"Cleaning up $prog: " -n + clog $"Cleaning up systemtap scripts: " -n if [ ! -d "$CACHE_PATH" ]; then do_success "no cache" return 0 @@ -630,6 +634,15 @@ cleanup () { fi } +# Restart scripts +function restart () { + [ -z "$OPT_SCRIPTS" ] && SCRIPTS=`get_all_runnings` + [ "$SCRIPTS" ] && stop + echo + start + return $? +} + RETVAL=0 case $CMD in @@ -642,13 +655,12 @@ case $CMD in RETVAL=$? ;; restart|force-reload) - stop - start + restart RETVAL=$? ;; status) status - RETVAL=$? + exit $? ;; compile) compile -- cgit From 6a35d102ce201e142f1133d9d5f0df6d47e3cd66 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Mon, 22 Jun 2009 16:48:30 +0200 Subject: PR10307 beginning of statement check should be overridden in guru mode. * tapsets.cxx (query_cu): When in guru mode just issue an warning (if not suppressed) instead of an error when address isn't at the beginning of a statement. --- tapsets.cxx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tapsets.cxx b/tapsets.cxx index 15dbeb81..bc09e168 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1639,6 +1639,7 @@ query_cu (Dwarf_Die * cudie, void * arg) // statement. This is a somewhat lame check that the address // is at the start of an assembly instruction. Mark probes are in the // middle of a macro and thus not strictly at a statement beginning. + // Guru mode may override this check. if (q->has_statement_num && ! q->has_mark) { Dwarf_Addr queryaddr = q->statement_num_val; @@ -1651,7 +1652,10 @@ query_cu (Dwarf_Die * cudie, void * arg) stringstream msg; msg << "address 0x" << hex << queryaddr << " does not match the beginning of a statement"; - throw semantic_error(msg.str()); + if (! q->sess.guru_mode) + throw semantic_error(msg.str()); + else if (! q->sess.suppress_warnings) + q->sess.print_warning(msg.str()); } } // Pick up [entrypc, name, DIE] tuples for all the functions -- cgit From 4116c576d5654287b0af598aee4a14eb2af73224 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Mon, 22 Jun 2009 16:59:31 +0200 Subject: PR10308 Beginning of statement check should provide alternatives. tapsets.cxx (query_cu): Add suggested address if found to error message. --- tapsets.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tapsets.cxx b/tapsets.cxx index bc09e168..7aee6930 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1652,6 +1652,8 @@ query_cu (Dwarf_Die * cudie, void * arg) stringstream msg; msg << "address 0x" << hex << queryaddr << " does not match the beginning of a statement"; + if (address_line) + msg << " (try 0x" << hex << lineaddr << ")"; if (! q->sess.guru_mode) throw semantic_error(msg.str()); else if (! q->sess.suppress_warnings) -- cgit