From d0bfd2ac518333369a384d58882ff37d5288225f Mon Sep 17 00:00:00 2001 From: Nobuhiro Tachino Date: Tue, 2 Feb 2010 12:19:18 -0500 Subject: rhbz 560890: preserve -L/-l variable ordering Switch to list from set for collecting available $var lists. Use O(N**2) list-uniqueifier that preserves initial ordering. --- elaborate.h | 3 ++- main.cxx | 53 +++++++++++++++++++++++++++++++++++++++++------------ tapset-mark.cxx | 10 +++++----- tapsets.cxx | 18 +++++++++--------- 4 files changed, 57 insertions(+), 27 deletions(-) diff --git a/elaborate.h b/elaborate.h index 30a02c5b..0a1549fb 100644 --- a/elaborate.h +++ b/elaborate.h @@ -17,6 +17,7 @@ #include #include #include +#include extern "C" { #include @@ -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 &arg_set) const {} + virtual void getargs (std::list &arg_set) const {} void printsig_nested (std::ostream &o) const; virtual void collect_derivation_chain (std::vector &probes_list); 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& l) +{ + list r; + set s; + + for (list::iterator i = l.begin(); i != l.end(); ++i) { + s.insert(*i); + } + + for (list::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 var_list; // format <"name:type",count> - map arg_list; + map var_count; // format <"name:type",count> + map arg_count; + list var_list; + list arg_list; // traverse set to collect all locals and arguments for (set::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 arg_set; + list arg_set; p->getargs(arg_set); - for (set::iterator ia=arg_set.begin(); ia!=arg_set.end(); ++ia) - arg_list[*ia]++; + for (list::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::iterator ir=var_list.begin(); ir!=var_list.end(); ++ir) - if (ir->second == it->second.size()) // print locals - o << " " << ir->first; - for (map::iterator ir=arg_list.begin(); ir!=arg_list.end(); ++ir) - if (ir->second == it->second.size()) // print arguments - o << " " << ir->first; + for (list::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::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/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 &arg_set) const; + void getargs (std::list &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 &arg_set) const +mark_derived_probe::getargs(std::list &arg_set) const { for (unsigned i = 0; i < mark_args.size(); i++) { @@ -473,13 +473,13 @@ mark_derived_probe::getargs(std::set &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/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 &arg_set) const; + void getargs(std::list &arg_set) const; void emit_unprivileged_assertion (translator_output*); void print_dupe_stamp(ostream& o); @@ -389,7 +389,7 @@ protected: {} private: - set args; + list 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 &arg_set) const +dwarf_derived_probe::getargs(std::list &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 args; void build_args(dwflpp& dw, Dwarf_Die& func_die); - void getargs (std::set &arg_set) const; + void getargs (std::list &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 &arg_set) const +tracepoint_derived_probe::getargs(std::list &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 -- cgit From a4f3198f0b774528ef17dfb1ce5b3e70b6eb82fb Mon Sep 17 00:00:00 2001 From: William Cohen Date: Tue, 2 Feb 2010 14:19:02 -0500 Subject: Add iodevstats.stp example --- testsuite/systemtap.examples/index.html | 3 ++ testsuite/systemtap.examples/index.txt | 12 ++++++++ testsuite/systemtap.examples/io/iodevstats.meta | 13 +++++++++ testsuite/systemtap.examples/io/iodevstats.stp | 39 +++++++++++++++++++++++++ testsuite/systemtap.examples/keyword-index.html | 6 ++++ testsuite/systemtap.examples/keyword-index.txt | 24 +++++++++++++++ 6 files changed, 97 insertions(+) create mode 100644 testsuite/systemtap.examples/io/iodevstats.meta create mode 100755 testsuite/systemtap.examples/io/iodevstats.stp diff --git a/testsuite/systemtap.examples/index.html b/testsuite/systemtap.examples/index.html index 294c6991..83c82d29 100644 --- a/testsuite/systemtap.examples/index.html +++ b/testsuite/systemtap.examples/index.html @@ -73,6 +73,9 @@ keywords: IO io/ioblktime.stp - Average Time Block IO Requests Spend in Queue
keywords: IO

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.

+
  • 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

    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.

  • diff --git a/testsuite/systemtap.examples/index.txt b/testsuite/systemtap.examples/index.txt index ebcd17a3..c435612c 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 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/keyword-index.html b/testsuite/systemtap.examples/keyword-index.html index 39d29031..7dcd05ce 100644 --- a/testsuite/systemtap.examples/keyword-index.html +++ b/testsuite/systemtap.examples/keyword-index.html @@ -165,6 +165,9 @@ keywords: IO io/ioblktime.stp - Average Time Block IO Requests Spend in Queue
    keywords: IO

    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.

    +
  • 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

    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.

  • @@ -324,6 +327,9 @@ keywords: PROCESS 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

      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.

    • diff --git a/testsuite/systemtap.examples/keyword-index.txt b/testsuite/systemtap.examples/keyword-index.txt index 96ad06bd..1066d277 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 @@ -670,6 +682,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 -- cgit From 111dd9ac1d5e127b80c89be484be37ea326b449d Mon Sep 17 00:00:00 2001 From: William Cohen Date: Tue, 2 Feb 2010 14:32:38 -0500 Subject: Add nfs_func_users example. --- testsuite/systemtap.examples/index.html | 3 +++ testsuite/systemtap.examples/index.txt | 10 ++++++++++ testsuite/systemtap.examples/io/nfs_func_users.meta | 13 +++++++++++++ testsuite/systemtap.examples/io/nfs_func_users.stp | 18 ++++++++++++++++++ testsuite/systemtap.examples/keyword-index.html | 6 ++++++ testsuite/systemtap.examples/keyword-index.txt | 20 ++++++++++++++++++++ 6 files changed, 70 insertions(+) create mode 100644 testsuite/systemtap.examples/io/nfs_func_users.meta create mode 100755 testsuite/systemtap.examples/io/nfs_func_users.stp diff --git a/testsuite/systemtap.examples/index.html b/testsuite/systemtap.examples/index.html index 83c82d29..f7190eab 100644 --- a/testsuite/systemtap.examples/index.html +++ b/testsuite/systemtap.examples/index.html @@ -91,6 +91,9 @@ keywords: IO
    • io/mbrwatch.stp - Monitor read/write of MBR (boot sector) area of block devices
      keywords: IO MONITORING

      The mbrwatch.stp script reports any attempted reads/writes of the first few sectors of a raw block device.

    • +
    • 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

      Every second print out the top ten executables sorted in descending order based on cumulative I/O traffic observed.

    • diff --git a/testsuite/systemtap.examples/index.txt b/testsuite/systemtap.examples/index.txt index c435612c..68741ffd 100644 --- a/testsuite/systemtap.examples/index.txt +++ b/testsuite/systemtap.examples/index.txt @@ -156,6 +156,16 @@ keywords: io monitoring first few sectors of a raw block device. +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/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 7dcd05ce..b49f48c3 100644 --- a/testsuite/systemtap.examples/keyword-index.html +++ b/testsuite/systemtap.examples/keyword-index.html @@ -183,6 +183,9 @@ keywords: IO
    • io/mbrwatch.stp - Monitor read/write of MBR (boot sector) area of block devices
      keywords: IO MONITORING

      The mbrwatch.stp script reports any attempted reads/writes of the first few sectors of a raw block device.

    • +
    • 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

      Every second print out the top ten executables sorted in descending order based on cumulative I/O traffic observed.

    • @@ -336,6 +339,9 @@ keywords: IO io/iostats.stp - List Executables Reading and Writing the Most Data
      keywords: IO PROFILING

      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.

      +
    • 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

      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.

    • diff --git a/testsuite/systemtap.examples/keyword-index.txt b/testsuite/systemtap.examples/keyword-index.txt index 1066d277..92370c83 100644 --- a/testsuite/systemtap.examples/keyword-index.txt +++ b/testsuite/systemtap.examples/keyword-index.txt @@ -311,6 +311,16 @@ keywords: io monitoring first few sectors of a raw block device. +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 @@ -713,6 +723,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 -- cgit From 3963c62757e752712592ebda63137cc7c6be532d Mon Sep 17 00:00:00 2001 From: William Cohen Date: Tue, 2 Feb 2010 14:53:20 -0500 Subject: Add nfs_func_log example. --- testsuite/systemtap.examples/index.html | 3 +++ testsuite/systemtap.examples/index.txt | 9 +++++++++ testsuite/systemtap.examples/keyword-index.html | 3 +++ testsuite/systemtap.examples/keyword-index.txt | 9 +++++++++ 4 files changed, 24 insertions(+) diff --git a/testsuite/systemtap.examples/index.html b/testsuite/systemtap.examples/index.html index f7190eab..eaf21135 100644 --- a/testsuite/systemtap.examples/index.html +++ b/testsuite/systemtap.examples/index.html @@ -91,6 +91,9 @@ keywords: IO
    • io/mbrwatch.stp - Monitor read/write of MBR (boot sector) area of block devices
      keywords: IO MONITORING

      The mbrwatch.stp script reports any attempted reads/writes of the 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.

    • diff --git a/testsuite/systemtap.examples/index.txt b/testsuite/systemtap.examples/index.txt index 68741ffd..9a3637ae 100644 --- a/testsuite/systemtap.examples/index.txt +++ b/testsuite/systemtap.examples/index.txt @@ -156,6 +156,15 @@ 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 diff --git a/testsuite/systemtap.examples/keyword-index.html b/testsuite/systemtap.examples/keyword-index.html index b49f48c3..ef1a801f 100644 --- a/testsuite/systemtap.examples/keyword-index.html +++ b/testsuite/systemtap.examples/keyword-index.html @@ -183,6 +183,9 @@ keywords: IO
    • io/mbrwatch.stp - Monitor read/write of MBR (boot sector) area of block devices
      keywords: IO MONITORING

      The mbrwatch.stp script reports any attempted reads/writes of the 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.

    • diff --git a/testsuite/systemtap.examples/keyword-index.txt b/testsuite/systemtap.examples/keyword-index.txt index 92370c83..0f1c5885 100644 --- a/testsuite/systemtap.examples/keyword-index.txt +++ b/testsuite/systemtap.examples/keyword-index.txt @@ -311,6 +311,15 @@ 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 -- cgit From fff4e6c6e4bb5bd1046164d697872f0bc1a48f4c Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 2 Feb 2010 16:14:39 -0600 Subject: Fix procfs_write.exp so that it will pass under RHELl5. * testsuite/systemtap.base/procfs_write.exp: Small changes for RHEL5 support. * testsuite/lib/stap_run.exp (stap_run): Increase maximum number of characters to match against. --- testsuite/lib/stap_run.exp | 4 ++++ testsuite/systemtap.base/procfs_write.exp | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) 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 -- cgit From 0d1ad607311857dc0b4666ce8a84c1a59c615ab9 Mon Sep 17 00:00:00 2001 From: Wenji Huang Date: Wed, 3 Feb 2010 10:21:24 +0800 Subject: PR9931: generate log to help diagnosing occasional cache hash collisions Ideas from Frank Ch. Eigler: - extending the hash.add() function to pass names along with the hash-mix values, so that class hash can internally track the hash-report string - storing the reports themselves in the cache, beside the .ko / .c files, and changing the cache-size-limit logic to delete these .txt files upon garbage collection * hash.h : New member parm_stream. * hash.cxx (get_parms): New function to convert parms stream to string. (hash::add): Aggregrate parms stream. (create_hash_log): New function to log hash operation. (find_*_hash): Log hash at the end of function. * cache.cxx (clean_cache): Remove log when cache reaches limitation. --- cache.cxx | 20 ++++++++++++++++++++ hash.cxx | 33 +++++++++++++++++++++++++++++++++ hash.h | 5 +++++ 3 files changed, 58 insertions(+) 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::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/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& 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 #include +#include +#include extern "C" { #include @@ -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); -- cgit From 23b7dbfaf1e9860f77b6bf1aa3da8610bf31b03c Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 3 Feb 2010 11:56:58 -0600 Subject: Fixed PR 11078. Changed code to avoided procfs race condition. * runtime/procfs.c: Allow STP_MAX_PROCFS_FILES define to be overridden. (_stp_create_procfs): Calls proc_create() instead of create_proc_entry() to avoid a race condition. * runtime/procfs-probes.c: New file containing procfs probe support routines. * tapset-procfs.cxx (procfs_derived_probe::join_group): Update struct _stp_procfs_data definition. (procfs_derived_probe::emit_module_decls): Include procfs-probes.c, which is where the definition of struct stap_procfs_probe exists. Update generated routines to read/write procfs data. (procfs_derived_probe_group::emit_module_init): Pass file_operations argument to _stp_create_procfs(). Initialize mutex. (procfs_var_expanding_visitor::visit_target_symbol): Update generated code. --- runtime/procfs-probes.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++ runtime/procfs.c | 15 +++- tapset-procfs.cxx | 114 ++++++++++++--------------- 3 files changed, 265 insertions(+), 68 deletions(-) create mode 100644 runtime/procfs-probes.c 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 +#include + +#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-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; -- cgit