summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Brolley <brolley@redhat.com>2010-02-04 11:31:47 -0500
committerDave Brolley <brolley@redhat.com>2010-02-04 11:31:47 -0500
commit8155cc835adb286c456f30ebaa961508bc064e90 (patch)
tree3634a392b6e0ef15f9426928bb23f30f58546f29
parentd2334a2233f4efd055dab021c603f7c046730a66 (diff)
parent23b7dbfaf1e9860f77b6bf1aa3da8610bf31b03c (diff)
downloadsystemtap-steved-8155cc835adb286c456f30ebaa961508bc064e90.tar.gz
systemtap-steved-8155cc835adb286c456f30ebaa961508bc064e90.tar.xz
systemtap-steved-8155cc835adb286c456f30ebaa961508bc064e90.zip
Merge branch 'master' of ssh://sources.redhat.com/git/systemtap
-rw-r--r--cache.cxx20
-rw-r--r--elaborate.h3
-rw-r--r--hash.cxx33
-rw-r--r--hash.h5
-rw-r--r--main.cxx53
-rw-r--r--runtime/procfs-probes.c204
-rw-r--r--runtime/procfs.c15
-rw-r--r--tapset-mark.cxx10
-rw-r--r--tapset-procfs.cxx114
-rw-r--r--tapsets.cxx18
-rw-r--r--testsuite/lib/stap_run.exp4
-rw-r--r--testsuite/systemtap.base/procfs_write.exp4
-rw-r--r--testsuite/systemtap.examples/index.html9
-rw-r--r--testsuite/systemtap.examples/index.txt31
-rw-r--r--testsuite/systemtap.examples/io/iodevstats.meta13
-rwxr-xr-xtestsuite/systemtap.examples/io/iodevstats.stp39
-rw-r--r--testsuite/systemtap.examples/io/nfs_func_users.meta13
-rwxr-xr-xtestsuite/systemtap.examples/io/nfs_func_users.stp18
-rw-r--r--testsuite/systemtap.examples/keyword-index.html15
-rw-r--r--testsuite/systemtap.examples/keyword-index.txt53
20 files changed, 577 insertions, 97 deletions
diff --git a/cache.cxx b/cache.cxx
index 29c20d0d..b113e019 100644
--- a/cache.cxx
+++ b/cache.cxx
@@ -282,6 +282,22 @@ clean_cache(systemtap_session& s)
globfree(&cache_glob);
+ // grab info for each staphash log file (.log)
+ glob_str = s.cache_path + "/*/*.log";
+ glob(glob_str.c_str(), 0, NULL, &cache_glob);
+ for (unsigned int i = 0; i < cache_glob.gl_pathc; i++)
+ {
+ string cache_ent_path = cache_glob.gl_pathv[i];
+ struct cache_ent_info cur_info(cache_ent_path, false);
+ if (cur_info.size != 0 && cur_info.weight != 0)
+ {
+ cache_size_b += cur_info.size;
+ cache_contents.insert(cur_info);
+ }
+ }
+
+ globfree(&cache_glob);
+
set<struct cache_ent_info>::iterator i;
unsigned long r_cache_size = cache_size_b;
string removed_dirs = "";
@@ -344,9 +360,11 @@ cache_ent_info::cache_ent_info(const string& path, bool is_module):
string mod_path = path + ".ko";
string modsgn_path = path + ".ko.sgn";
string source_path = path + ".c";
+ string hash_path = path + ".log";
size = get_file_size(mod_path)
+ get_file_size(modsgn_path);
+ get_file_size(source_path);
+ + get_file_size(hash_path);
weight = get_file_weight(mod_path);
}
else
@@ -365,9 +383,11 @@ cache_ent_info::unlink() const
string mod_path = path + ".ko";
string modsgn_path = path + ".ko.sgn";
string source_path = path + ".c";
+ string hash_path = path + ".log";
::unlink(mod_path.c_str());
::unlink(modsgn_path.c_str());
::unlink(source_path.c_str());
+ ::unlink(hash_path.c_str());
}
else
::unlink(path.c_str());
diff --git a/elaborate.h b/elaborate.h
index 30a02c5b..0a1549fb 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -17,6 +17,7 @@
#include <iosfwd>
#include <sstream>
#include <map>
+#include <list>
extern "C" {
#include <elfutils/libdw.h>
@@ -129,7 +130,7 @@ struct derived_probe: public probe
virtual probe_point* sole_location () const;
virtual void printsig (std::ostream &o) const;
// return arguments of probe if there
- virtual void getargs (std::set<std::string> &arg_set) const {}
+ virtual void getargs (std::list<std::string> &arg_set) const {}
void printsig_nested (std::ostream &o) const;
virtual void collect_derivation_chain (std::vector<probe*> &probes_list);
diff --git a/hash.cxx b/hash.cxx
index a4589577..8664bb63 100644
--- a/hash.cxx
+++ b/hash.cxx
@@ -43,6 +43,7 @@ hash::start()
void
hash::add(const unsigned char *buffer, size_t size)
{
+ parm_stream << "," << buffer;
mdfour_update(&md4, buffer, size);
}
@@ -60,6 +61,16 @@ hash::add_file(const std::string& filename)
add(st.st_mtime);
}
+string
+hash::get_parms()
+{
+ string parms_str = parm_stream.str();
+
+ parm_stream.clear();
+ if (!parms_str.empty())
+ parms_str.erase(parms_str.begin()); // skip leading ","
+ return parms_str;
+}
void
hash::result(string& r)
@@ -78,6 +89,20 @@ hash::result(string& r)
r = rstream.str();
}
+void create_hash_log(const string &type_str, const string &parms, const string &result, const string &hash_log_path)
+{
+ ofstream log_file;
+ time_t rawtime;
+ time ( &rawtime );
+ string time_str(ctime (&rawtime));
+
+ log_file.open(hash_log_path.c_str());
+ log_file << "[" << time_str.substr(0,time_str.length()-1); // erase terminated '\n'
+ log_file << "]" << type_str;
+ log_file << ": " << parms << endl;
+ log_file << "result:" << result << endl;
+ log_file.close();
+}
static void
get_base_hash (systemtap_session& s, hash& h)
@@ -229,6 +254,8 @@ find_script_hash (systemtap_session& s, const string& script, const hash &base)
// Update C source name with new module_name.
s.translated_source = string(s.tmpdir) + "/" + s.module_name + ".c";
+ create_hash_log(string("script_hash"), h.get_parms(), result,
+ hashdir + "/" + s.module_name + "_hash.log");
}
@@ -249,6 +276,8 @@ find_stapconf_hash (systemtap_session& s, const hash& base)
s.stapconf_name = "stapconf_" + result + ".h";
s.stapconf_path = hashdir + "/" + s.stapconf_name;
+ create_hash_log(string("stapconf_hash"), h.get_parms(), result,
+ hashdir + "/stapconf_" + result + "_hash.log");
}
@@ -282,6 +311,8 @@ find_tracequery_hash (systemtap_session& s, const vector<string>& headers)
if (!create_hashdir(s, result, hashdir))
return "";
+ create_hash_log(string("tracequery_hash"), h.get_parms(), result,
+ hashdir + "/tracequery_" + result + "_hash.log");
return hashdir + "/tracequery_" + result + ".ko";
}
@@ -306,6 +337,8 @@ find_typequery_hash (systemtap_session& s, const string& name)
if (!create_hashdir(s, result, hashdir))
return "";
+ create_hash_log(string("typequery_hash"), h.get_parms(), result,
+ hashdir + "/typequery_" + result + "_hash.log");
return hashdir + "/typequery_" + result
+ (name[0] == 'k' ? ".ko" : ".so");
}
diff --git a/hash.h b/hash.h
index 6bb1c78a..173f8e51 100644
--- a/hash.h
+++ b/hash.h
@@ -1,5 +1,7 @@
#include <string>
#include <vector>
+#include <sstream>
+#include <fstream>
extern "C" {
#include <string.h>
@@ -13,9 +15,11 @@ class hash
{
private:
struct mdfour md4;
+ std::ostringstream parm_stream;
public:
hash() { start(); }
+ hash(const hash &base) { start(); parm_stream << base.parm_stream.str();}
void start();
@@ -34,6 +38,7 @@ public:
void add_file(const std::string& filename);
void result(std::string& r);
+ std::string get_parms();
};
void find_hash (systemtap_session& s, const std::string& script);
diff --git a/main.cxx b/main.cxx
index cbedd6e4..0126f323 100644
--- a/main.cxx
+++ b/main.cxx
@@ -156,6 +156,26 @@ usage (systemtap_session& s, int exitcode)
}
+static void uniq_list(list<string>& l)
+{
+ list<string> r;
+ set<string> s;
+
+ for (list<string>::iterator i = l.begin(); i != l.end(); ++i) {
+ s.insert(*i);
+ }
+
+ for (list<string>::iterator i = l.begin(); i != l.end(); ++i) {
+ if (s.find(*i) != s.end()) {
+ s.erase(*i);
+ r.push_back(*i);
+ }
+ }
+
+ l.clear();
+ l.assign(r.begin(), r.end());
+}
+
static void
printscript(systemtap_session& s, ostream& o)
{
@@ -211,8 +231,10 @@ printscript(systemtap_session& s, ostream& o)
// Print the locals and arguments for -L mode only
if (s.listing_mode_vars)
{
- map<string,unsigned> var_list; // format <"name:type",count>
- map<string,unsigned> arg_list;
+ map<string,unsigned> var_count; // format <"name:type",count>
+ map<string,unsigned> arg_count;
+ list<string> var_list;
+ list<string> arg_list;
// traverse set<derived_probe *> to collect all locals and arguments
for (set<derived_probe *>::iterator ix=it->second.begin(); ix!=it->second.end(); ++ix)
{
@@ -223,21 +245,28 @@ printscript(systemtap_session& s, ostream& o)
stringstream tmps;
vardecl* v = p->locals[j];
v->printsig (tmps);
- var_list[tmps.str()]++;
+ var_count[tmps.str()]++;
+ var_list.push_back(tmps.str());
}
// collect arguments of the probe if there
- set<string> arg_set;
+ list<string> arg_set;
p->getargs(arg_set);
- for (set<string>::iterator ia=arg_set.begin(); ia!=arg_set.end(); ++ia)
- arg_list[*ia]++;
+ for (list<string>::iterator ia=arg_set.begin(); ia!=arg_set.end(); ++ia) {
+ arg_count[*ia]++;
+ arg_list.push_back(*ia);
+ }
}
+
+ uniq_list(arg_list);
+ uniq_list(var_list);
+
// print the set-intersection only
- for (map<string,unsigned>::iterator ir=var_list.begin(); ir!=var_list.end(); ++ir)
- if (ir->second == it->second.size()) // print locals
- o << " " << ir->first;
- for (map<string,unsigned>::iterator ir=arg_list.begin(); ir!=arg_list.end(); ++ir)
- if (ir->second == it->second.size()) // print arguments
- o << " " << ir->first;
+ for (list<string>::iterator ir=var_list.begin(); ir!=var_list.end(); ++ir)
+ if (var_count.find(*ir)->second == it->second.size()) // print locals
+ o << " " << *ir;
+ for (list<string>::iterator ir=arg_list.begin(); ir!=arg_list.end(); ++ir)
+ if (arg_count.find(*ir)->second == it->second.size()) // print arguments
+ o << " " << *ir;
}
o << endl;
}
diff --git a/runtime/procfs-probes.c b/runtime/procfs-probes.c
new file mode 100644
index 00000000..73aa7e5f
--- /dev/null
+++ b/runtime/procfs-probes.c
@@ -0,0 +1,204 @@
+#ifndef _STP_PROCFS_PROBES_C_
+#define _STP_PROCFS_PROBES_C_
+
+#include <linux/mutex.h>
+#include <linux/fs.h>
+
+#if 0
+// Currently we have to output _stp_procfs_data early in the
+// translation process. It really should go here.
+struct _stp_procfs_data {
+ char *buffer;
+ unsigned long count;
+};
+#endif
+
+struct stap_procfs_probe {
+ const char *path;
+ const char *read_pp;
+ void (*read_ph) (struct context*);
+ const char *write_pp;
+ void (*write_ph) (struct context*);
+
+ // FIXME: Eventually, this could get bigger than MAXSTRINGLEN
+ // when we support 'probe procfs("file").read.maxbuf(8192)'
+ // (bug 10690).
+ string_t buffer;
+ size_t count;
+
+ int needs_fill;
+ struct mutex lock;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+ atomic_t lockcount;
+#endif
+};
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16)
+/*
+ * Kernels 2.6.16 or less don't really have mutexes. The 'mutex_*'
+ * functions are defined as their similar semaphore equivalents.
+ * However, there is no semaphore equivalent of 'mutex_is_locked'.
+ * So, we'll fake it with an atomic counter.
+ */
+static inline void _spp_lock_init(struct stap_procfs_probe *spp)
+{
+ atomic_set(&spp->lockcount, 0);
+ mutex_init(&spp->lock);
+}
+static inline int _spp_trylock(struct stap_procfs_probe *spp)
+{
+ int ret = mutex_trylock(&spp->lock);
+ if (ret) {
+ atomic_inc(&spp->lockcount);
+ }
+ return(ret);
+}
+static inline void _spp_lock(struct stap_procfs_probe *spp)
+{
+ mutex_lock(&spp->lock);
+ atomic_inc(&spp->lockcount);
+}
+static inline void _spp_unlock(struct stap_procfs_probe *spp)
+{
+ atomic_dec(&spp->lockcount);
+ mutex_unlock(&spp->lock);
+}
+static inline void _spp_lock_shutdown(struct stap_procfs_probe *spp)
+{
+ if (atomic_read(&spp->lockcount) != 0) {
+ _spp_unlock(spp);
+ }
+ mutex_destroy(&spp->lock);
+}
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) */
+#define _spp_lock_init(spp) mutex_init(&(spp)->lock)
+#define _spp_trylock(spp) mutex_trylock(&(spp)->lock)
+#define _spp_lock(spp) mutex_lock(&(spp)->lock)
+#define _spp_unlock(spp) mutex_unlock(&(spp)->lock)
+static inline void _spp_lock_shutdown(struct stap_procfs_probe *spp)
+{
+ if (mutex_is_locked(&spp->lock)) {
+ mutex_unlock(&spp->lock);
+ }
+ mutex_destroy(&spp->lock);
+}
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) */
+
+static int _stp_proc_fill_read_buffer(struct stap_procfs_probe *spp);
+
+static int _stp_process_write_buffer(struct stap_procfs_probe *spp,
+ const char __user *buf, size_t count);
+
+static int
+_stp_proc_open_file(struct inode *inode, struct file *filp)
+{
+ struct stap_procfs_probe *spp;
+ int err;
+
+ spp = (struct stap_procfs_probe *)PDE(inode)->data;
+ if (spp == NULL) {
+ return -EINVAL;
+ }
+
+ err = generic_file_open(inode, filp);
+ if (err)
+ return err;
+
+ /* To avoid concurrency problems, we only allow 1 open at a
+ * time. (Grabbing a mutex here doesn't really work. The
+ * debug kernel can OOPS with "BUG: lock held when returning
+ * to user space!".)
+ *
+ * If open() was called with
+ * O_NONBLOCK, don't block, just return EAGAIN. */
+ if (filp->f_flags & O_NONBLOCK) {
+ if (_spp_trylock(spp) == 0) {
+ return -EAGAIN;
+ }
+ }
+ else {
+ _spp_lock(spp);
+ }
+
+ filp->private_data = spp;
+ if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
+ spp->buffer[0] = '\0';
+ spp->count = 0;
+ spp->needs_fill = 1;
+ }
+ return 0;
+}
+
+static int
+_stp_proc_release_file(struct inode *inode, struct file *filp)
+{
+ struct stap_procfs_probe *spp;
+
+ spp = (struct stap_procfs_probe *)filp->private_data;
+ if (spp != NULL) {
+ _spp_unlock(spp);
+ }
+ return 0;
+}
+
+static ssize_t
+_stp_proc_read_file(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct stap_procfs_probe *spp = file->private_data;
+ ssize_t retval = 0;
+
+ /* If we don't have a probe read function, just return 0 to
+ * indicate there isn't any data here. */
+ if (spp == NULL || spp->read_ph == NULL) {
+ goto out;
+ }
+
+ /* If needed, fill up the buffer.*/
+ if (spp->needs_fill) {
+ if ((retval = _stp_proc_fill_read_buffer(spp))) {
+ goto out;
+ }
+ }
+
+ /* Return bytes from the buffer. */
+ retval = simple_read_from_buffer(buf, count, ppos, spp->buffer,
+ spp->count);
+out:
+ return retval;
+}
+
+static ssize_t
+_stp_proc_write_file(struct file *file, const char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct stap_procfs_probe *spp = file->private_data;
+ struct _stp_procfs_data pdata;
+ ssize_t len;
+
+ /* If we don't have a write probe, return EIO. */
+ if (spp->write_ph == NULL) {
+ len = -EIO;
+ goto out;
+ }
+
+ /* Handle the input buffer. */
+ len = _stp_process_write_buffer(spp, buf, count);
+ if (len > 0) {
+ *ppos += len;
+ }
+
+out:
+ return len;
+}
+
+static struct file_operations _stp_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = _stp_proc_open_file,
+ .read = _stp_proc_read_file,
+ .write = _stp_proc_write_file,
+ .llseek = generic_file_llseek,
+ .release = _stp_proc_release_file
+};
+
+#endif /* _STP_PROCFS_PROBES_C_ */
diff --git a/runtime/procfs.c b/runtime/procfs.c
index 1d2ad837..1fd9fcc5 100644
--- a/runtime/procfs.c
+++ b/runtime/procfs.c
@@ -17,7 +17,10 @@
#ifndef _STP_PROCFS_C_
#define _STP_PROCFS_C_
+#ifndef STP_MAX_PROCFS_FILES
#define STP_MAX_PROCFS_FILES 16
+#endif
+
static int _stp_num_pde = 0;
static struct proc_dir_entry *_stp_pde[STP_MAX_PROCFS_FILES];
static struct proc_dir_entry *_stp_procfs_files[STP_MAX_PROCFS_FILES];
@@ -131,7 +134,8 @@ static struct proc_dir_entry *_stp_procfs_lookup(const char *dir, struct proc_di
return NULL;
}
-static int _stp_create_procfs(const char *path, int num)
+static int _stp_create_procfs(const char *path, int num,
+ const struct file_operations *fops)
{
const char *p;
char *next;
@@ -182,15 +186,18 @@ static int _stp_create_procfs(const char *path, int num)
if (_stp_num_pde == STP_MAX_PROCFS_FILES)
goto too_many;
- de = create_proc_entry (p, 0600, last_dir);
+ de = proc_create(p, 0600, last_dir, fops);
if (de == NULL) {
_stp_error("Could not create file \"%s\" in path \"%s\"\n", p, path);
goto err;
}
- _stp_pde[_stp_num_pde++] = de;
- _stp_procfs_files[num] = de;
+#ifdef AUTOCONF_PROCFS_OWNER
+ de->owner = THIS_MODULE;
+#endif
de->uid = _stp_uid;
de->gid = _stp_gid;
+ _stp_pde[_stp_num_pde++] = de;
+ _stp_procfs_files[num] = de;
return 0;
too_many:
diff --git a/tapset-mark.cxx b/tapset-mark.cxx
index 1ce3c919..6dbc55dc 100644
--- a/tapset-mark.cxx
+++ b/tapset-mark.cxx
@@ -59,7 +59,7 @@ struct mark_derived_probe: public derived_probe
void print_dupe_stamp (ostream& o);
void emit_probe_context_vars (translator_output* o);
void initialize_probe_context_vars (translator_output* o);
- void getargs (std::set<std::string> &arg_set) const;
+ void getargs (std::list<std::string> &arg_set) const;
void parse_probe_format ();
};
@@ -465,7 +465,7 @@ mark_derived_probe::initialize_probe_context_vars (translator_output* o)
}
void
-mark_derived_probe::getargs(std::set<std::string> &arg_set) const
+mark_derived_probe::getargs(std::list<std::string> &arg_set) const
{
for (unsigned i = 0; i < mark_args.size(); i++)
{
@@ -473,13 +473,13 @@ mark_derived_probe::getargs(std::set<std::string> &arg_set) const
switch (mark_args[i]->stp_type)
{
case pe_long:
- arg_set.insert(localname+":long");
+ arg_set.push_back(localname+":long");
break;
case pe_string:
- arg_set.insert(localname+":string");
+ arg_set.push_back(localname+":string");
break;
default:
- arg_set.insert(localname+":unknown");
+ arg_set.push_back(localname+":unknown");
break;
}
}
diff --git a/tapset-procfs.cxx b/tapset-procfs.cxx
index f5ab95f8..c4eb54f3 100644
--- a/tapset-procfs.cxx
+++ b/tapset-procfs.cxx
@@ -110,8 +110,7 @@ procfs_derived_probe::join_group (systemtap_session& s)
embeddedcode *ec = new embeddedcode;
ec->tok = NULL;
ec->code = string("struct _stp_procfs_data {\n")
- + string(" const char *buffer;\n")
- + string(" off_t off;\n")
+ + string(" char *buffer;\n")
+ string(" unsigned long count;\n")
+ string("};\n");
s.embeds.push_back(ec);
@@ -164,15 +163,10 @@ procfs_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "/* ---- procfs probes ---- */";
s.op->newline() << "#include \"procfs.c\"";
+ s.op->newline() << "#include \"procfs-probes.c\"";
// Emit the procfs probe data list
- s.op->newline() << "static struct stap_procfs_probe {";
- s.op->newline(1)<< "const char *path;";
- s.op->newline() << "const char *read_pp;";
- s.op->newline() << "void (*read_ph) (struct context*);";
- s.op->newline() << "const char *write_pp;";
- s.op->newline() << "void (*write_ph) (struct context*);";
- s.op->newline(-1) << "} stap_procfs_probes[] = {";
+ s.op->newline() << "static struct stap_procfs_probe stap_procfs_probes[] = {";
s.op->indent(1);
for (p_b_p_iterator it = probes_by_path.begin(); it != probes_by_path.end();
@@ -212,21 +206,20 @@ procfs_derived_probe_group::emit_module_decls (systemtap_session& s)
}
s.op->newline(-1) << "};";
+ // Output routine to fill in the buffer with our data. Note that we
+ // need to do this even in the case where we have no read probes,
+ // but we can skip most of it then.
+ s.op->newline();
+
+ s.op->newline() << "static int _stp_proc_fill_read_buffer(struct stap_procfs_probe *spp) {";
+ s.op->indent(1);
if (has_read_probes)
{
- // Output routine to fill in 'page' with our data.
- s.op->newline();
-
- s.op->newline() << "static int _stp_procfs_read(char *page, char **start, off_t off, int count, int *eof, void *data) {";
-
- s.op->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;";
s.op->newline() << "struct _stp_procfs_data pdata;";
common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "spp->read_pp");
- s.op->newline() << "pdata.buffer = page;";
- s.op->newline() << "pdata.off = off;";
- s.op->newline() << "pdata.count = count;";
+ s.op->newline() << "pdata.buffer = spp->buffer;";
s.op->newline() << "if (c->data == NULL)";
s.op->newline(1) << "c->data = &pdata;";
s.op->newline(-1) << "else {";
@@ -242,29 +235,37 @@ procfs_derived_probe_group::emit_module_decls (systemtap_session& s)
// call probe function
s.op->newline() << "(*spp->read_ph) (c);";
- // Note that _procfs_value_set copied string data into 'page'
+ // Note that _procfs_value_set copied string data into spp->buffer
s.op->newline() << "c->data = NULL;";
+ s.op->newline() << "spp->needs_fill = 0;";
+ s.op->newline() << "spp->count = strlen(spp->buffer);";
+
common_probe_entryfn_epilogue (s.op);
- s.op->newline() << "if (pdata.count == 0)";
- s.op->newline(1) << "*eof = 1;";
- s.op->indent(-1);
- s.op->newline() << "return pdata.count;";
+ s.op->newline() << "if (spp->needs_fill) {";
+ s.op->newline(1) << "spp->needs_fill = 0;";
+ s.op->newline() << "return -EIO;";
s.op->newline(-1) << "}";
}
+ s.op->newline() << "return 0;";
+ s.op->newline(-1) << "}";
+
+ // Output routine to read data. Note that we need to do this even
+ // in the case where we have no write probes, but we can skip most
+ // of it then.
+ s.op->newline() << "static int _stp_process_write_buffer(struct stap_procfs_probe *spp, const char __user *buf, size_t count) {";
+ s.op->indent(1);
+ s.op->newline() << "int retval = 0;";
if (has_write_probes)
{
- s.op->newline() << "static int _stp_procfs_write(struct file *file, const char *buffer, unsigned long count, void *data) {";
-
- s.op->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;";
s.op->newline() << "struct _stp_procfs_data pdata;";
common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "spp->write_pp");
- s.op->newline() << "if (count > (MAXSTRINGLEN - 1))";
+ s.op->newline() << "if (count >= MAXSTRINGLEN)";
s.op->newline(1) << "count = MAXSTRINGLEN - 1;";
s.op->indent(-1);
- s.op->newline() << "pdata.buffer = buffer;";
+ s.op->newline() << "pdata.buffer = (char *)buf;";
s.op->newline() << "pdata.count = count;";
s.op->newline() << "if (c->data == NULL)";
@@ -283,11 +284,14 @@ procfs_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "(*spp->write_ph) (c);";
s.op->newline() << "c->data = NULL;";
- common_probe_entryfn_epilogue (s.op);
-
- s.op->newline() << "return count;";
+ s.op->newline() << "if (c->last_error == 0) {";
+ s.op->newline(1) << "retval = count;";
s.op->newline(-1) << "}";
+
+ common_probe_entryfn_epilogue (s.op);
}
+ s.op->newline() << "return retval;";
+ s.op->newline(-1) << "}";
}
@@ -304,36 +308,21 @@ procfs_derived_probe_group::emit_module_init (systemtap_session& s)
s.op->newline(1) << "probe_point = spp->read_pp;";
s.op->newline(-1) << "else";
s.op->newline(1) << "probe_point = spp->write_pp;";
+ s.op->indent(-1);
- s.op->newline(-1) << "rc = _stp_create_procfs(spp->path, i);";
+ s.op->newline() << "_spp_lock_init(spp);";
+ s.op->newline() << "rc = _stp_create_procfs(spp->path, i, &_stp_proc_fops);";
s.op->newline() << "if (rc) {";
s.op->newline(1) << "_stp_close_procfs();";
+
+ s.op->newline() << "for (i = 0; i < " << probes_by_path.size() << "; i++) {";
+ s.op->newline(1) << "spp = &stap_procfs_probes[i];";
+ s.op->newline() << "_spp_lock_shutdown(spp);";
+ s.op->newline(-1) << "}";
s.op->newline() << "break;";
s.op->newline(-1) << "}";
- if (has_read_probes)
- {
- s.op->newline() << "if (spp->read_pp)";
- s.op->newline(1) << "_stp_procfs_files[i]->read_proc = &_stp_procfs_read;";
- s.op->newline(-1) << "else";
- s.op->newline(1) << "_stp_procfs_files[i]->read_proc = NULL;";
- s.op->indent(-1);
- }
- else
- s.op->newline() << "_stp_procfs_files[i]->read_proc = NULL;";
-
- if (has_write_probes)
- {
- s.op->newline() << "if (spp->write_pp)";
- s.op->newline(1) << "_stp_procfs_files[i]->write_proc = &_stp_procfs_write;";
- s.op->newline(-1) << "else";
- s.op->newline(1) << "_stp_procfs_files[i]->write_proc = NULL;";
- s.op->indent(-1);
- }
- else
- s.op->newline() << "_stp_procfs_files[i]->write_proc = NULL;";
-
s.op->newline() << "_stp_procfs_files[i]->data = spp;";
s.op->newline(-1) << "}"; // for loop
}
@@ -346,6 +335,10 @@ procfs_derived_probe_group::emit_module_exit (systemtap_session& s)
return;
s.op->newline() << "_stp_close_procfs();";
+ s.op->newline() << "for (i = 0; i < " << probes_by_path.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_procfs_probe *spp = &stap_procfs_probes[i];";
+ s.op->newline() << "_spp_lock_shutdown(spp);";
+ s.op->newline(-1) << "}";
}
@@ -378,8 +371,7 @@ procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e)
embeddedcode *ec = new embeddedcode;
ec->tok = e->tok;
- string fname = (string(lvalue ? "_procfs_value_set" : "_procfs_value_get")
- + "_" + lex_cast(tick++));
+ string fname = (string(lvalue ? "_procfs_value_set" : "_procfs_value_get"));
string locvalue = "CONTEXT->data";
if (! lvalue)
@@ -391,14 +383,8 @@ procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e)
ec->code = string("int bytes = 0;\n")
+ string(" struct _stp_procfs_data *data = (struct _stp_procfs_data *)(") + locvalue + string(");\n")
+ string(" bytes = strnlen(THIS->value, MAXSTRINGLEN - 1);\n")
- + string(" if (data->off >= bytes)\n")
- + string(" bytes = 0;\n")
- + string(" else {\n")
- + string(" bytes -= data->off;\n")
- + string(" if (bytes > data->count)\n")
- + string(" bytes = data->count;\n")
- + string(" memcpy((void *)data->buffer, THIS->value + data->off, bytes);\n")
- + string(" }\n")
+ + string(" memcpy((void *)data->buffer, THIS->value, bytes);\n")
+ + string(" data->buffer[bytes] = '\\0';\n")
+ string(" data->count = bytes;\n");
fdecl->name = fname;
diff --git a/tapsets.cxx b/tapsets.cxx
index 0711411e..916e4ddf 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -364,7 +364,7 @@ struct dwarf_derived_probe: public derived_probe
void printsig (std::ostream &o) const;
virtual void join_group (systemtap_session& s);
void emit_probe_local_init(translator_output * o);
- void getargs(std::set<std::string> &arg_set) const;
+ void getargs(std::list<std::string> &arg_set) const;
void emit_unprivileged_assertion (translator_output*);
void print_dupe_stamp(ostream& o);
@@ -389,7 +389,7 @@ protected:
{}
private:
- set<string> args;
+ list<string> args;
void saveargs(dwarf_query& q, Dwarf_Die* scope_die, dwarf_var_expanding_visitor& v);
};
@@ -3046,7 +3046,7 @@ dwarf_derived_probe::saveargs(dwarf_query& q, Dwarf_Die* scope_die, dwarf_var_ex
if (has_return &&
dwarf_attr_die (scope_die, DW_AT_type, &type_die) &&
dwarf_type_name(&type_die, type_name))
- args.insert("$return:"+type_name);
+ args.push_back("$return:"+type_name);
/* Pretend that we aren't in a .return for a moment, just so we can
* check whether variables are accessible. We don't want any of the
@@ -3092,7 +3092,7 @@ dwarf_derived_probe::saveargs(dwarf_query& q, Dwarf_Die* scope_die, dwarf_var_ex
tsym->saved_conversion_error = 0;
v.require (tsym);
if (!tsym->saved_conversion_error)
- args.insert("$"+string(arg_name)+":"+type_name);
+ args.push_back("$"+string(arg_name)+":"+type_name);
}
while (dwarf_siblingof (&arg, &arg) == 0);
@@ -3102,9 +3102,9 @@ dwarf_derived_probe::saveargs(dwarf_query& q, Dwarf_Die* scope_die, dwarf_var_ex
void
-dwarf_derived_probe::getargs(std::set<std::string> &arg_set) const
+dwarf_derived_probe::getargs(std::list<std::string> &arg_set) const
{
- arg_set.insert(args.begin(), args.end());
+ arg_set.insert(arg_set.end(), args.begin(), args.end());
}
@@ -5678,7 +5678,7 @@ struct tracepoint_derived_probe: public derived_probe
vector <struct tracepoint_arg> args;
void build_args(dwflpp& dw, Dwarf_Die& func_die);
- void getargs (std::set<std::string> &arg_set) const;
+ void getargs (std::list<std::string> &arg_set) const;
void join_group (systemtap_session& s);
void print_dupe_stamp(ostream& o);
void emit_probe_context_vars (translator_output* o);
@@ -6066,11 +6066,11 @@ tracepoint_derived_probe::build_args(dwflpp& dw, Dwarf_Die& func_die)
}
void
-tracepoint_derived_probe::getargs(std::set<std::string> &arg_set) const
+tracepoint_derived_probe::getargs(std::list<std::string> &arg_set) const
{
for (unsigned i = 0; i < args.size(); ++i)
if (args[i].usable)
- arg_set.insert("$"+args[i].name+":"+args[i].c_type);
+ arg_set.push_back("$"+args[i].name+":"+args[i].c_type);
}
void
diff --git a/testsuite/lib/stap_run.exp b/testsuite/lib/stap_run.exp
index 9d271ca1..42ea09c9 100644
--- a/testsuite/lib/stap_run.exp
+++ b/testsuite/lib/stap_run.exp
@@ -57,6 +57,10 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args }
# check the output to see if it is sane
set output "^systemtap ending probe\r\n$OUTPUT_CHECK_STRING"
+ # By default, "expect -re" will match up to 2000 chars.
+ # Increase this to 8K worth of data.
+ exp_match_max 8192
+
expect {
-timeout 20
-re $warning_regexp {
diff --git a/testsuite/systemtap.base/procfs_write.exp b/testsuite/systemtap.base/procfs_write.exp
index 5bb35532..68338b8c 100644
--- a/testsuite/systemtap.base/procfs_write.exp
+++ b/testsuite/systemtap.base/procfs_write.exp
@@ -96,8 +96,8 @@ set test_string \
# Now we need the version of the above string that expect will look
# for. So, we need to convert all '\n' to '\r\n' and add a trailing
# '\r\n'.
-regsub -all {\n} $test_string {\r\n} test_string2
-set test_string2 "$test_string2\\r\\n"
+regsub -all {\n} $test_string "\r\n" test_string2
+set test_string2 "$test_string2\r\n"
proc proc_write_test {} {
global test test_string
diff --git a/testsuite/systemtap.examples/index.html b/testsuite/systemtap.examples/index.html
index 294c6991..eaf21135 100644
--- a/testsuite/systemtap.examples/index.html
+++ b/testsuite/systemtap.examples/index.html
@@ -73,6 +73,9 @@ keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#BAC
<li><a href="io/ioblktime.stp">io/ioblktime.stp</a> - Average Time Block IO Requests Spend in Queue <br>
keywords: <a href="keyword-index.html#IO">IO</a> <br>
<p>The ioblktime.stp script tracks the amount of time that each block IO requests spend waiting for completion. The script computes the average waiting time for block IO per device and prints list every 10 seconds. In some cases there can be too many outstanding block IO operations and the script may exceed the default number of MAXMAPENTRIES allowed. In this case the allowed number can be increased with "-DMAXMAPENTRIES=10000" option on the stap command line.</p></li>
+<li><a href="io/iodevstats.stp">io/iodevstats.stp</a> - List Executables Reading and Writing the Most Data by Device<br>
+keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#PROFILING">PROFILING</a> <br>
+<p> The iodevstats.stp script measures the amount of data successfully read and written by all the executables for each io device on the system. The output is sorted from greatest sum of bytes read and written to a device by an executable to the least. The output contains device major/minor number, the count of operations (reads and writes), the totals and averages for the number of bytes read and written.</p></li>
<li><a href="io/iostat-scsi.stp">io/iostat-scsi.stp</a> - iostat for SCSI Devices<br>
keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#PROFILING">PROFILING</a> <a href="keyword-index.html#SCSI">SCSI</a> <br>
<p>The iostat-scsi.stp script provides a breakdown of the number of blks read and written on the machine's various SCSI devices. The script takes one argument which is the number of seconds between reports.</p></li>
@@ -88,6 +91,12 @@ keywords: <a href="keyword-index.html#IO">IO</a> <br>
<li><a href="io/mbrwatch.stp">io/mbrwatch.stp</a> - Monitor read/write of MBR (boot sector) area of block devices<br>
keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#MONITORING">MONITORING</a> <br>
<p> The mbrwatch.stp script reports any attempted reads/writes of the first few sectors of a raw block device.</p></li>
+<li><a href="io/nfs_func_log.stp">io/nfs_func_log.stp</a> - Print Log of NFS Functions Used<br>
+keywords: <a href="keyword-index.html#IO">IO</a> <br>
+<p>The nfs_func_log.stp script logs the uses of NFS functions in the kernel. The output is a trace. Each line contains the time stamp, the process name, and the process number followed by the function name.</p></li>
+<li><a href="io/nfs_func_users.stp">io/nfs_func_users.stp</a> - Tally the Number of NFS Functions Used by Each Process<br>
+keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#PROFILING">PROFILING</a> <br>
+<p>The nfs_func_users.stp script counts the uses of NFS functions in the kernel on a per process bases. The output is sorted from the process with the greatest number of NFS functions called to the least. The output contains the executable name, the process number, and the total number of NFS functions called by the process.</p></li>
<li><a href="io/traceio.stp">io/traceio.stp</a> - Track Cumulative I/O Activity by Process Name<br>
keywords: <a href="keyword-index.html#IO">IO</a> <br>
<p>Every second print out the top ten executables sorted in descending order based on cumulative I/O traffic observed.</p></li>
diff --git a/testsuite/systemtap.examples/index.txt b/testsuite/systemtap.examples/index.txt
index ebcd17a3..9a3637ae 100644
--- a/testsuite/systemtap.examples/index.txt
+++ b/testsuite/systemtap.examples/index.txt
@@ -95,6 +95,18 @@ keywords: io
line.
+io/iodevstats.stp - List Executables Reading and Writing the Most Data by Device
+keywords: io profiling
+
+ The iodevstats.stp script measures the amount of data successfully
+ read and written by all the executables for each io device on the
+ system. The output is sorted from greatest sum of bytes read and
+ written to a device by an executable to the least. The output
+ contains device major/minor number, the count of operations (reads
+ and writes), the totals and averages for the number of bytes read and
+ written.
+
+
io/iostat-scsi.stp - iostat for SCSI Devices
keywords: io profiling scsi
@@ -144,6 +156,25 @@ keywords: io monitoring
first few sectors of a raw block device.
+io/nfs_func_log.stp - Print Log of NFS Functions Used
+keywords: io
+
+ The nfs_func_log.stp script logs the uses of NFS functions in the
+ kernel. The output is a trace. Each line contains the time stamp,
+ the process name, and the process number followed by the function
+ name.
+
+
+io/nfs_func_users.stp - Tally the Number of NFS Functions Used by Each Process
+keywords: io profiling
+
+ The nfs_func_users.stp script counts the uses of NFS functions in the
+ kernel on a per process bases. The output is sorted from the process
+ with the greatest number of NFS functions called to the least. The
+ output contains the executable name, the process number, and the
+ total number of NFS functions called by the process.
+
+
io/traceio.stp - Track Cumulative I/O Activity by Process Name
keywords: io
diff --git a/testsuite/systemtap.examples/io/iodevstats.meta b/testsuite/systemtap.examples/io/iodevstats.meta
new file mode 100644
index 00000000..89277d2f
--- /dev/null
+++ b/testsuite/systemtap.examples/io/iodevstats.meta
@@ -0,0 +1,13 @@
+title: List Executables Reading and Writing the Most Data by Device
+name: iodevstats.stp
+version: 1.0
+author: anonymous
+keywords: io profiling
+subsystem: io
+status: production
+exit: user-controlled
+output: sorted-list
+scope: system-wide
+description: The iodevstats.stp script measures the amount of data successfully read and written by all the executables for each io device on the system. The output is sorted from greatest sum of bytes read and written to a device by an executable to the least. The output contains device major/minor number, the count of operations (reads and writes), the totals and averages for the number of bytes read and written.
+test_check: stap -p4 iodevstats.stp
+test_installcheck: stap iodevstats.stp -c "sleep 0.2"
diff --git a/testsuite/systemtap.examples/io/iodevstats.stp b/testsuite/systemtap.examples/io/iodevstats.stp
new file mode 100755
index 00000000..8925945f
--- /dev/null
+++ b/testsuite/systemtap.examples/io/iodevstats.stp
@@ -0,0 +1,39 @@
+#! /usr/bin/env stap
+global reads, writes, totals
+
+probe begin { printf("starting probe\n") }
+
+probe vfs.read.return {
+ count = $return
+ if ( count >= 0 ) {
+ e=execname();
+ reads[e,dev] <<< count # statistics array
+ totals[e,dev] += count
+ }
+}
+
+probe vfs.write.return {
+ count = $return
+ if (count >= 0 ) {
+ e=execname();
+ writes[e,dev] <<< count # statistics array
+ totals[e,dev] += count
+ }
+}
+
+probe end {
+ printf("\n%16s %8s %8s %8s %8s %8s %8s %8s\n",
+ "", "", "", "read", "read", "", "write", "write")
+ printf("%16s %8s %8s %8s %8s %8s %8s %8s\n",
+ "name", "device", "read", "KB tot", "B avg", "write", "KB tot", "B avg")
+ foreach ([name,dev] in totals- limit 20) { # sort by total io
+ printf("%16s %3d, %4d %8d %8d %8d %8d %8d %8d\n",
+ name, _dev_major(dev), _dev_minor(dev),
+ @count(reads[name,dev]),
+ (@count(reads[name,dev]) ? @sum(reads[name,dev])>>10 : 0 ),
+ (@count(reads[name,dev]) ? @avg(reads[name,dev]) : 0 ),
+ @count(writes[name,dev]),
+ (@count(writes[name,dev]) ? @sum(writes[name,dev])>>10 : 0 ),
+ (@count(writes[name,dev]) ? @avg(writes[name,dev]) : 0 ))
+ }
+}
diff --git a/testsuite/systemtap.examples/io/nfs_func_users.meta b/testsuite/systemtap.examples/io/nfs_func_users.meta
new file mode 100644
index 00000000..e37d401a
--- /dev/null
+++ b/testsuite/systemtap.examples/io/nfs_func_users.meta
@@ -0,0 +1,13 @@
+title: Tally the Number of NFS Functions Used by Each Process
+name: nfs_func_users.stp
+version: 1.0
+author: William Cohen
+keywords: io profiling
+subsystem: io
+status: production
+exit: user-controlled
+output: sorted-list
+scope: system-wide
+description: The nfs_func_users.stp script counts the uses of NFS functions in the kernel on a per process bases. The output is sorted from the process with the greatest number of NFS functions called to the least. The output contains the executable name, the process number, and the total number of NFS functions called by the process.
+test_check: stap -p4 nfs_func_users.stp
+test_installcheck: stap nfs_func_users.stp -c "sleep 0.2"
diff --git a/testsuite/systemtap.examples/io/nfs_func_users.stp b/testsuite/systemtap.examples/io/nfs_func_users.stp
new file mode 100755
index 00000000..010db420
--- /dev/null
+++ b/testsuite/systemtap.examples/io/nfs_func_users.stp
@@ -0,0 +1,18 @@
+#!/usr/bin/env stap
+
+global nfsdcalls
+
+probe begin {
+ printf("Collecting top NFSD procs...\n")
+}
+
+probe kernel.function("*@fs/nfs/*proc.c") ?,
+ module("nfs").function("*@fs/nfs/*proc.c") ? {
+ nfsdcalls[execname(), pid()]++
+}
+
+probe end {
+ printf("\nname(pid) nfs ops\n");
+ foreach ([name,p] in nfsdcalls- limit 20)
+ printf("%s(%d) %d\n", name, p, nfsdcalls[name, p])
+}
diff --git a/testsuite/systemtap.examples/keyword-index.html b/testsuite/systemtap.examples/keyword-index.html
index 39d29031..ef1a801f 100644
--- a/testsuite/systemtap.examples/keyword-index.html
+++ b/testsuite/systemtap.examples/keyword-index.html
@@ -165,6 +165,9 @@ keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#BAC
<li><a href="io/ioblktime.stp">io/ioblktime.stp</a> - Average Time Block IO Requests Spend in Queue <br>
keywords: <a href="keyword-index.html#IO">IO</a> <br>
<p>The ioblktime.stp script tracks the amount of time that each block IO requests spend waiting for completion. The script computes the average waiting time for block IO per device and prints list every 10 seconds. In some cases there can be too many outstanding block IO operations and the script may exceed the default number of MAXMAPENTRIES allowed. In this case the allowed number can be increased with "-DMAXMAPENTRIES=10000" option on the stap command line.</p></li>
+<li><a href="io/iodevstats.stp">io/iodevstats.stp</a> - List Executables Reading and Writing the Most Data by Device<br>
+keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#PROFILING">PROFILING</a> <br>
+<p> The iodevstats.stp script measures the amount of data successfully read and written by all the executables for each io device on the system. The output is sorted from greatest sum of bytes read and written to a device by an executable to the least. The output contains device major/minor number, the count of operations (reads and writes), the totals and averages for the number of bytes read and written.</p></li>
<li><a href="io/iostat-scsi.stp">io/iostat-scsi.stp</a> - iostat for SCSI Devices<br>
keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#PROFILING">PROFILING</a> <a href="keyword-index.html#SCSI">SCSI</a> <br>
<p>The iostat-scsi.stp script provides a breakdown of the number of blks read and written on the machine's various SCSI devices. The script takes one argument which is the number of seconds between reports.</p></li>
@@ -180,6 +183,12 @@ keywords: <a href="keyword-index.html#IO">IO</a> <br>
<li><a href="io/mbrwatch.stp">io/mbrwatch.stp</a> - Monitor read/write of MBR (boot sector) area of block devices<br>
keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#MONITORING">MONITORING</a> <br>
<p> The mbrwatch.stp script reports any attempted reads/writes of the first few sectors of a raw block device.</p></li>
+<li><a href="io/nfs_func_log.stp">io/nfs_func_log.stp</a> - Print Log of NFS Functions Used<br>
+keywords: <a href="keyword-index.html#IO">IO</a> <br>
+<p>The nfs_func_log.stp script logs the uses of NFS functions in the kernel. The output is a trace. Each line contains the time stamp, the process name, and the process number followed by the function name.</p></li>
+<li><a href="io/nfs_func_users.stp">io/nfs_func_users.stp</a> - Tally the Number of NFS Functions Used by Each Process<br>
+keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#PROFILING">PROFILING</a> <br>
+<p>The nfs_func_users.stp script counts the uses of NFS functions in the kernel on a per process bases. The output is sorted from the process with the greatest number of NFS functions called to the least. The output contains the executable name, the process number, and the total number of NFS functions called by the process.</p></li>
<li><a href="io/traceio.stp">io/traceio.stp</a> - Track Cumulative I/O Activity by Process Name<br>
keywords: <a href="keyword-index.html#IO">IO</a> <br>
<p>Every second print out the top ten executables sorted in descending order based on cumulative I/O traffic observed.</p></li>
@@ -324,12 +333,18 @@ keywords: <a href="keyword-index.html#PROCESS">PROCESS</a> <a href="keyword-inde
</ul>
<h3><a name="PROFILING">PROFILING</a></h3>
<ul>
+<li><a href="io/iodevstats.stp">io/iodevstats.stp</a> - List Executables Reading and Writing the Most Data by Device<br>
+keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#PROFILING">PROFILING</a> <br>
+<p> The iodevstats.stp script measures the amount of data successfully read and written by all the executables for each io device on the system. The output is sorted from greatest sum of bytes read and written to a device by an executable to the least. The output contains device major/minor number, the count of operations (reads and writes), the totals and averages for the number of bytes read and written.</p></li>
<li><a href="io/iostat-scsi.stp">io/iostat-scsi.stp</a> - iostat for SCSI Devices<br>
keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#PROFILING">PROFILING</a> <a href="keyword-index.html#SCSI">SCSI</a> <br>
<p>The iostat-scsi.stp script provides a breakdown of the number of blks read and written on the machine's various SCSI devices. The script takes one argument which is the number of seconds between reports.</p></li>
<li><a href="io/iostats.stp">io/iostats.stp</a> - List Executables Reading and Writing the Most Data<br>
keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#PROFILING">PROFILING</a> <br>
<p> The iostat.stp script measures the amount of data successfully read and written by all the executables on the system. The output is sorted from most greatest sum of bytes read and written by an executable to the least. The output contains the count of operations (opens, reads, and writes), the totals and averages for the number of bytes read and written.</p></li>
+<li><a href="io/nfs_func_users.stp">io/nfs_func_users.stp</a> - Tally the Number of NFS Functions Used by Each Process<br>
+keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#PROFILING">PROFILING</a> <br>
+<p>The nfs_func_users.stp script counts the uses of NFS functions in the kernel on a per process bases. The output is sorted from the process with the greatest number of NFS functions called to the least. The output contains the executable name, the process number, and the total number of NFS functions called by the process.</p></li>
<li><a href="process/pf2.stp">process/pf2.stp</a> - Profile kernel functions<br>
keywords: <a href="keyword-index.html#PROFILING">PROFILING</a> <br>
<p>The pf2.stp script sets up time-based sampling. Every five seconds it prints out a sorted list with the top ten kernel functions with samples.</p></li>
diff --git a/testsuite/systemtap.examples/keyword-index.txt b/testsuite/systemtap.examples/keyword-index.txt
index 96ad06bd..0f1c5885 100644
--- a/testsuite/systemtap.examples/keyword-index.txt
+++ b/testsuite/systemtap.examples/keyword-index.txt
@@ -250,6 +250,18 @@ keywords: io
line.
+io/iodevstats.stp - List Executables Reading and Writing the Most Data by Device
+keywords: io profiling
+
+ The iodevstats.stp script measures the amount of data successfully
+ read and written by all the executables for each io device on the
+ system. The output is sorted from greatest sum of bytes read and
+ written to a device by an executable to the least. The output
+ contains device major/minor number, the count of operations (reads
+ and writes), the totals and averages for the number of bytes read and
+ written.
+
+
io/iostat-scsi.stp - iostat for SCSI Devices
keywords: io profiling scsi
@@ -299,6 +311,25 @@ keywords: io monitoring
first few sectors of a raw block device.
+io/nfs_func_log.stp - Print Log of NFS Functions Used
+keywords: io
+
+ The nfs_func_log.stp script logs the uses of NFS functions in the
+ kernel. The output is a trace. Each line contains the time stamp,
+ the process name, and the process number followed by the function
+ name.
+
+
+io/nfs_func_users.stp - Tally the Number of NFS Functions Used by Each Process
+keywords: io profiling
+
+ The nfs_func_users.stp script counts the uses of NFS functions in the
+ kernel on a per process bases. The output is sorted from the process
+ with the greatest number of NFS functions called to the least. The
+ output contains the executable name, the process number, and the
+ total number of NFS functions called by the process.
+
+
io/traceio.stp - Track Cumulative I/O Activity by Process Name
keywords: io
@@ -670,6 +701,18 @@ keywords: process scheduler time tracepoint
= PROFILING =
+io/iodevstats.stp - List Executables Reading and Writing the Most Data by Device
+keywords: io profiling
+
+ The iodevstats.stp script measures the amount of data successfully
+ read and written by all the executables for each io device on the
+ system. The output is sorted from greatest sum of bytes read and
+ written to a device by an executable to the least. The output
+ contains device major/minor number, the count of operations (reads
+ and writes), the totals and averages for the number of bytes read and
+ written.
+
+
io/iostat-scsi.stp - iostat for SCSI Devices
keywords: io profiling scsi
@@ -689,6 +732,16 @@ keywords: io profiling
bytes read and written.
+io/nfs_func_users.stp - Tally the Number of NFS Functions Used by Each Process
+keywords: io profiling
+
+ The nfs_func_users.stp script counts the uses of NFS functions in the
+ kernel on a per process bases. The output is sorted from the process
+ with the greatest number of NFS functions called to the least. The
+ output contains the executable name, the process number, and the
+ total number of NFS functions called by the process.
+
+
process/pf2.stp - Profile kernel functions
keywords: profiling