diff options
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | Makefile.in | 21 | ||||
-rwxr-xr-x | configure | 77 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | coveragedb.cxx | 322 | ||||
-rw-r--r-- | coveragedb.h | 70 | ||||
-rw-r--r-- | elaborate.cxx | 28 | ||||
-rw-r--r-- | elaborate.h | 1 | ||||
-rw-r--r-- | main.cxx | 20 | ||||
-rw-r--r-- | session.h | 5 | ||||
-rw-r--r-- | staptree.cxx | 25 | ||||
-rw-r--r-- | staptree.h | 5 | ||||
-rw-r--r-- | systemtap.spec.in | 2 |
13 files changed, 574 insertions, 9 deletions
diff --git a/Makefile.am b/Makefile.am index 5c9a37d0..4b81c83d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,8 +15,8 @@ bin_PROGRAMS = stap staprun stap_SOURCES = main.cxx \ parse.cxx staptree.cxx elaborate.cxx translate.cxx \ tapsets.cxx buildrun.cxx loc2c.c hash.cxx mdfour.c \ - cache.cxx util.cxx -stap_LDADD = @stap_LIBS@ + cache.cxx util.cxx coveragedb.cxx +stap_LDADD = @stap_LIBS@ -lsqlite3 stap_CXXFLAGS = $(AM_CXXFLAGS) stap_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/Makefile.in b/Makefile.in index 2bfa676e..1b1ff3f8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -96,7 +96,7 @@ am_stap_OBJECTS = stap-main.$(OBJEXT) stap-parse.$(OBJEXT) \ stap-translate.$(OBJEXT) stap-tapsets.$(OBJEXT) \ stap-buildrun.$(OBJEXT) stap-loc2c.$(OBJEXT) \ stap-hash.$(OBJEXT) stap-mdfour.$(OBJEXT) stap-cache.$(OBJEXT) \ - stap-util.$(OBJEXT) + stap-util.$(OBJEXT) stap-coveragedb.$(OBJEXT) stap_OBJECTS = $(am_stap_OBJECTS) stap_LINK = $(CXXLD) $(stap_CXXFLAGS) $(CXXFLAGS) $(stap_LDFLAGS) \ $(LDFLAGS) -o $@ @@ -268,9 +268,9 @@ dist_man_MANS = stap.1 stapprobes.5 stapfuncs.5 stapex.5 staprun.8 lket.5 lket-b stap_SOURCES = main.cxx \ parse.cxx staptree.cxx elaborate.cxx translate.cxx \ tapsets.cxx buildrun.cxx loc2c.c hash.cxx mdfour.c \ - cache.cxx util.cxx + cache.cxx util.cxx coveragedb.cxx -stap_LDADD = @stap_LIBS@ +stap_LDADD = @stap_LIBS@ -lsqlite3 stap_CXXFLAGS = $(AM_CXXFLAGS) stap_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_1) stap_LDFLAGS = $(AM_LDFLAGS) $(am__append_2) @@ -478,6 +478,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loc2c_test-loc2c.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-buildrun.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-cache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-coveragedb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-elaborate.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-hash.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-loc2c.Po@am__quote@ @@ -817,6 +818,20 @@ stap-util.obj: util.cxx @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='util.cxx' object='stap-util.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-util.obj `if test -f 'util.cxx'; then $(CYGPATH_W) 'util.cxx'; else $(CYGPATH_W) '$(srcdir)/util.cxx'; fi` + +stap-coveragedb.o: coveragedb.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-coveragedb.o -MD -MP -MF $(DEPDIR)/stap-coveragedb.Tpo -c -o stap-coveragedb.o `test -f 'coveragedb.cxx' || echo '$(srcdir)/'`coveragedb.cxx +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-coveragedb.Tpo $(DEPDIR)/stap-coveragedb.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='coveragedb.cxx' object='stap-coveragedb.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-coveragedb.o `test -f 'coveragedb.cxx' || echo '$(srcdir)/'`coveragedb.cxx + +stap-coveragedb.obj: coveragedb.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-coveragedb.obj -MD -MP -MF $(DEPDIR)/stap-coveragedb.Tpo -c -o stap-coveragedb.obj `if test -f 'coveragedb.cxx'; then $(CYGPATH_W) 'coveragedb.cxx'; else $(CYGPATH_W) '$(srcdir)/coveragedb.cxx'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-coveragedb.Tpo $(DEPDIR)/stap-coveragedb.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='coveragedb.cxx' object='stap-coveragedb.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-coveragedb.obj `if test -f 'coveragedb.cxx'; then $(CYGPATH_W) 'coveragedb.cxx'; else $(CYGPATH_W) '$(srcdir)/coveragedb.cxx'; fi` install-man1: $(man1_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" @@ -6657,6 +6657,83 @@ fi { echo "$as_me:$LINENO: stap will link $stap_LIBS" >&5 echo "$as_me: stap will link $stap_LIBS" >&6;} + +{ echo "$as_me:$LINENO: checking for sqlite3_open in -lsqlite3" >&5 +echo $ECHO_N "checking for sqlite3_open in -lsqlite3... $ECHO_C" >&6; } +if test "${ac_cv_lib_sqlite3_sqlite3_open+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsqlite3 $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sqlite3_open (); +int +main () +{ +return sqlite3_open (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_sqlite3_sqlite3_open=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_sqlite3_sqlite3_open=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_sqlite3_sqlite3_open" >&5 +echo "${ECHO_T}$ac_cv_lib_sqlite3_sqlite3_open" >&6; } +if test $ac_cv_lib_sqlite3_sqlite3_open = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSQLITE3 1 +_ACEOF + + LIBS="-lsqlite3 $LIBS" + +else + + { { echo "$as_me:$LINENO: error: missing sqlite development headers/libraries" >&5 +echo "$as_me: error: missing sqlite development headers/libraries" >&2;} + { (exit 1); exit 1; }; } +fi + + date=`date +%Y-%m-%d` cat >>confdefs.h <<_ACEOF diff --git a/configure.ac b/configure.ac index 5b0c75ee..ec619094 100644 --- a/configure.ac +++ b/configure.ac @@ -140,6 +140,9 @@ fi AC_SUBST(stap_LIBS) AC_MSG_NOTICE([stap will link $stap_LIBS]) +AC_CHECK_HEADER(sqlite3.h, AC_CHECK_LIB(sqlite3, sqlite3_open, + AC_MSG_ERROR([missing sqlite development headers/libraries])]) + dnl Plop in the build (configure) date date=`date +%Y-%m-%d` AC_DEFINE_UNQUOTED(DATE, "$date", [Configuration/build date]) diff --git a/coveragedb.cxx b/coveragedb.cxx new file mode 100644 index 00000000..69eb95b4 --- /dev/null +++ b/coveragedb.cxx @@ -0,0 +1,322 @@ +// coveragedb.cxx +// Copyright (C) 2007 Red Hat Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. + +#include "parse.h" +#include "coveragedb.h" +#include "config.h" +#include "elaborate.h" +#include "tapsets.h" +#include "session.h" +#include "util.h" + +#include <iostream> +#include <sqlite3.h> + +using namespace std; + +void print_coverage_info(systemtap_session &s) +{ + vector<derived_probe*> used_probe_list; + vector<derived_probe*> unused_probe_list; + // print out used probes + clog << "---- used probes-----" << endl; + for (unsigned i=0; i<s.probes.size(); i++) { + // walk through the chain of probes + s.probes[i]->collect_derivation_chain(used_probe_list); + for (unsigned j=0; j<used_probe_list.size(); ++j) { + for (unsigned k=0; k< used_probe_list[j]->locations.size(); ++k) + clog << "probe: " + << used_probe_list[j]->locations[k]->tok->location << endl; + } + + clog << "----" << endl; + // for each probe print used and unused variables + for (unsigned j=0; j<s.probes[i]->locals.size(); ++j) { + clog << "local: " << s.probes[i]->locals[j]->tok->location << endl; + } + for (unsigned j=0; j<s.probes[i]->unused_locals.size(); ++j) { + clog << "unused_local: " + << s.probes[i]->unused_locals[j]->tok->location + << endl; + } + } + // print out unused probes + clog << "---- unused probes----- " << endl; + for (unsigned i=0; i<s.unused_probes.size(); i++) { + // walk through the chain of probes + s.probes[i]->collect_derivation_chain(unused_probe_list); + for (unsigned j=0; j<unused_probe_list.size(); ++j) { + for (unsigned k=0; k< unused_probe_list[j]->locations.size(); ++k) + clog << "probe: " + << unused_probe_list[j]->locations[k]->tok->location << endl; + } + + } + // print out used functions + clog << "---- used functions----- " << endl; + for (unsigned i=0; i<s.functions.size(); i++) { + clog << "function: " << s.functions[i]->tok->location + << " " << s.functions[i]->name + << endl; + } + // print out unused functions + clog << "---- unused functions----- " << endl; + for (unsigned i=0; i<s.unused_functions.size(); i++) { + clog << "unused_function: " << s.unused_functions[i]->tok->location + << " " << s.unused_functions[i]->name + << endl; + } + // print out used globals + clog << "---- used globals----- " << endl; + for (unsigned i=0; i<s.globals.size(); i++) { + clog << "globals: " << s.globals[i]->tok->location + << " " << s.globals[i]->name + << endl; + } + // print out unused globals + clog << "---- unused globals----- " << endl; + for (unsigned i=0; i<s.unused_globals.size(); i++) { + clog << "globals: " << s.unused_globals[i]->tok->location + << " " << s.unused_globals[i]->name + << endl; + } +} + + +void sql_stmt(sqlite3 *db, const char* stmt) +{ + char *errmsg; + int ret; + + // cerr << "sqlite: " << stmt << endl; + + ret = sqlite3_exec(db, stmt, 0, 0, &errmsg); + + if(ret != SQLITE_OK) { + cerr << "Error in statement: " << stmt << " [" << errmsg << "]." + << endl; + } +} + +void enter_element(sqlite3 *db, coverage_element &x) +{ + ostringstream command; + command << "insert or ignore into counts values ('" + << x.file << "', '" + << x.line << "', '" + << x.col << "', '" + << x.type << "','" + << x.name << "', '" + << x.parent <<"'," + << "'0', '0', '0')"; + sql_stmt(db, command.str().c_str()); +} + +void increment_element(sqlite3 *db, coverage_element &x) +{ + // make sure value in table + enter_element(db, x); + // increment appropriate value + if (x.compiled) { + ostringstream command; + command << "update counts set compiled = compiled + " + << x.compiled << " where (" + << "file == '" << x.file << "' and " + << "line == '" << x.line << "' and " + << "col == '" << x.col << "')"; + sql_stmt(db, command.str().c_str()); + } + if (x.removed) { + ostringstream command; + command << "update counts set removed = removed + " + << x.removed << " where (" + << "file == '" << x.file << "' and " + << "line == '" << x.line << "' and " + << "col == '" << x.col << "')"; + sql_stmt(db, command.str().c_str()); + } +} + + +void +sql_update_used_probes(sqlite3 *db, systemtap_session &s) +{ + vector<derived_probe*> used_probe_list; + + // update database used probes + for (unsigned i=0; i<s.probes.size(); i++) { + // walk through the chain of probes + s.probes[i]->collect_derivation_chain(used_probe_list); + for (unsigned j=0; j<used_probe_list.size(); ++j) { + for (unsigned k=0; k< used_probe_list[j]->locations.size(); ++k){ + struct source_loc place = used_probe_list[j]->locations[k]->tok->location; + coverage_element x(place); + + x.type = string("p"); + x.name = used_probe_list[j]->locations[k]->str(); + x.compiled = 1; + increment_element(db, x); + } + } + + // for each probe update used and unused variables + for (unsigned j=0; j<s.probes[i]->locals.size(); ++j) { + struct source_loc place = s.probes[i]->locals[j]->tok->location; + coverage_element x(place); + + x.type = string("l"); + x.name = s.probes[i]->locals[j]->tok->content; + x.compiled = 1; + increment_element(db, x); + } + for (unsigned j=0; j<s.probes[i]->unused_locals.size(); ++j) { + struct source_loc place = s.probes[i]->unused_locals[j]->tok->location; + coverage_element x(place); + + x.type = string("l"); + x.name = s.probes[i]->unused_locals[j]->tok->content; + x.removed = 1; + increment_element(db, x); + } + } +} + + +void +sql_update_unused_probes(sqlite3 *db, systemtap_session &s) +{ + vector<derived_probe*> unused_probe_list; + + // update database unused probes + for (unsigned i=0; i<s.unused_probes.size(); i++) { + // walk through the chain of probes + s.probes[i]->collect_derivation_chain(unused_probe_list); + for (unsigned j=0; j<unused_probe_list.size(); ++j) { + for (unsigned k=0; k< unused_probe_list[j]->locations.size(); ++k) { + + struct source_loc place = unused_probe_list[j]->locations[k]->tok->location; + coverage_element x(place); + + x.type = string("p"); + x.name = unused_probe_list[j]->locations[k]->str(); + x.removed = 1; + increment_element(db, x); + } + } + } +} + + +void +sql_update_used_functions(sqlite3 *db, systemtap_session &s) +{ + // update db used functions + for (unsigned i=0; i<s.functions.size(); i++) { + struct source_loc place = s.functions[i]->tok->location; + coverage_element x(place); + + x.type = string("f"); + x.name = s.functions[i]->name; + x.compiled = 1; + increment_element(db, x); + } +} + + +void +sql_update_unused_functions(sqlite3 *db, systemtap_session &s) +{ + // update db unused functions + for (unsigned i=0; i<s.unused_functions.size(); i++) { + struct source_loc place = s.unused_functions[i]->tok->location; + coverage_element x(place); + + x.type = string("f"); + x.name = s.unused_functions[i]->name; + x.removed = 1; + increment_element(db, x); + } +} + + +void +sql_update_used_globals(sqlite3 *db, systemtap_session &s) +{ + // update db used globals + for (unsigned i=0; i<s.globals.size(); i++) { + sql_stmt(db, "--"); + struct source_loc place = s.globals[i]->tok->location; + coverage_element x(place); + + x.type = string("g"); + x.name = s.globals[i]->name; + x.compiled = 1; + increment_element(db, x); + } +} + + +void +sql_update_unused_globals(sqlite3 *db, systemtap_session &s) +{ + // update db unused globals + for (unsigned i=0; i<s.unused_globals.size(); i++) { + struct source_loc place = s.unused_globals[i]->tok->location; + coverage_element x(place); + + x.type = string("g"); + x.name = s.unused_globals[i]->name; + x.removed = 1; + increment_element(db, x); + } +} + + + +void update_coverage_db(systemtap_session &s) +{ + sqlite3 *db; + int rc; + + string filename(s.data_path + "/" + s.kernel_release + ".db"); + + rc = sqlite3_open(filename.c_str(), &db); + if( rc ){ + cerr << "Can't open database: " << sqlite3_errmsg(db) << endl; + sqlite3_close(db); + exit(EXIT_FAILURE); + } + + string create_table("create table if not exists counts (" + "file text, line integer, col integer, " + "type text, name text, parent text, " + "compiled integer, removed integer, executed integer, " + "primary key (file, line, col))" + ); + + // lock the database + sql_stmt(db, "begin"); + + // update the number counts on things + sql_stmt(db, create_table.c_str()); + + if (s.verbose >2) + print_coverage_info(s); + + sql_update_used_probes(db, s); + sql_update_unused_probes(db, s); + sql_update_used_functions(db, s); + sql_update_unused_functions(db, s); + sql_update_used_globals(db, s); + sql_update_unused_globals(db, s); + + // unlock the database and close database + sql_stmt(db, "commit"); + + sqlite3_close(db); +} diff --git a/coveragedb.h b/coveragedb.h new file mode 100644 index 00000000..5b62ba8b --- /dev/null +++ b/coveragedb.h @@ -0,0 +1,70 @@ +// coveragedb.cxx +// Copyright (C) 2007 Red Hat Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. + +#ifndef COVERAGEDB_H +#define COVERAGEDB_H + +#include "session.h" + +#include <string> + + +/* + +tuples: file, line number, column, type of object, name +values: number of times object "pulled_in", number of times "removed", +times executed + +if (compiled == 0) object never compiled +if (compiled > 0) object compiled +if (removed > 0) object parsed +if (executed == 0) never executed +if (executed > 0) executed + + +Want to make sure that the data base accurately reflects testing. +1) atomic updates, either commit all or none of information +2) only update coverage db compile info, if compile successful +3) only update coverage db execute info, if instrumentation run suscessfully + + +Would like to have something that looks for interesting features in db: + +list which things are not compile +list which things are not exectuted + +ratio of compiled/total (overall, by file, by line) +ratio of executed/total (overall, by file, by line) + +*/ + +class coverage_element { +public: + std::string file; + int line; + int col; + std::string type; + std::string name; + std::string parent; + int compiled; + int removed; + int executed; + + coverage_element() { line = 0; col = 0; + compiled = 0; removed = 0; executed = 0; } + + coverage_element(source_loc &place) { + file = place.file; line = place.line; col = place.column; + compiled = 0; removed = 0; executed = 0; } +}; + +void print_coverage_info(systemtap_session &s); +void update_coverage_db(systemtap_session &s); + +#endif + diff --git a/elaborate.cxx b/elaborate.cxx index 82d2a5d9..0bd1c3eb 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -96,6 +96,14 @@ derived_probe::printsig_nested (ostream& o) const } +void +derived_probe::collect_derivation_chain (std::vector<derived_probe*> &probes_list) +{ + probes_list.push_back(this); + base->collect_derivation_chain(probes_list); +} + + probe_point* derived_probe::sole_location () const { @@ -424,9 +432,9 @@ alias_expansion_builder // The new probe gets the location list of the alias, n->locations = alias->locations; - // the token location of the use, - n->tok = use->tok; - n->body->tok = use->tok; + // the token location of the alias, + n->tok = location->tok; + n->body->tok = location->tok; // and statements representing the concatenation of the alias' // body with the use's. @@ -1367,6 +1375,9 @@ void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p) if (s.verbose>2) clog << "Eliding unused function " << s.functions[i]->name << endl; + if (s.tapset_compile_coverage) { + s.unused_functions.push_back (s.functions[i]); + } s.functions.erase (s.functions.begin() + i); relaxed_p = false; // NB: don't increment i @@ -1407,6 +1418,10 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p) if (s.verbose>2) clog << "Eliding unused local variable " << l->name << " in " << s.probes[i]->name << endl; + if (s.tapset_compile_coverage) { + s.probes[i]->unused_locals.push_back + (s.probes[i]->locals[j]); + } s.probes[i]->locals.erase(s.probes[i]->locals.begin() + j); relaxed_p = false; // don't increment j @@ -1425,6 +1440,10 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p) clog << "Eliding unused local variable " << l->name << " in function " << s.functions[i]->name << endl; + if (s.tapset_compile_coverage) { + s.functions[i]->unused_locals.push_back + (s.functions[i]->locals[j]); + } s.functions[i]->locals.erase(s.functions[i]->locals.begin() + j); relaxed_p = false; // don't increment j @@ -1441,6 +1460,9 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p) if (s.verbose>2) clog << "Eliding unused global variable " << l->name << endl; + if (s.tapset_compile_coverage) { + s.unused_globals.push_back(s.globals[i]); + } s.globals.erase(s.globals.begin() + i); relaxed_p = false; // don't increment i diff --git a/elaborate.h b/elaborate.h index ec49e126..6967e1e7 100644 --- a/elaborate.h +++ b/elaborate.h @@ -118,6 +118,7 @@ struct derived_probe: public probe virtual probe_point* sole_location () const; virtual void printsig (std::ostream &o) const; void printsig_nested (std::ostream &o) const; + virtual void collect_derivation_chain (std::vector<derived_probe*> &probes_list); virtual void emit_probe_context_vars (translator_output*) {} // From within unparser::emit_common_header, add any extra variables @@ -18,6 +18,7 @@ #include "hash.h" #include "cache.h" #include "util.h" +#include "coveragedb.h" #include <iostream> #include <fstream> @@ -99,6 +100,8 @@ usage (systemtap_session& s, int exitcode) << endl << " -x PID sets target() to PID" << endl << " -t collect probe timing information" << endl + << " -q generate information on tapset coverage" + << endl ; // -d: dump safety-related external references @@ -216,6 +219,7 @@ main (int argc, char * const argv []) s.perfmon=0; s.symtab = false; s.use_cache = true; + s.tapset_compile_coverage = false; const char* s_p = getenv ("SYSTEMTAP_TAPSET"); if (s_p != NULL) @@ -262,10 +266,14 @@ main (int argc, char * const argv []) } } + const char* s_tc = getenv ("SYSTEMTAP_COVERAGE"); + if (s_tc != NULL) + s.tapset_compile_coverage = true; + while (true) { // NB: also see find_hash(), help(), switch stmt below, stap.1 man page - int grc = getopt (argc, argv, "hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:u"); + int grc = getopt (argc, argv, "hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uq"); if (grc < 0) break; switch (grc) @@ -402,6 +410,10 @@ main (int argc, char * const argv []) s.macros.push_back (string (optarg)); break; + case 'q': + s.tapset_compile_coverage = true; + break; + case 'h': usage (s, 0); break; @@ -787,6 +799,12 @@ pass_5: // if (rc) goto cleanup; cleanup: + + // update the database information + if (!rc && s.tapset_compile_coverage) { + update_coverage_db(s); + } + // Clean up temporary directory. Obviously, be careful with this. if (s.tmpdir == "") ; // do nothing @@ -97,6 +97,7 @@ struct systemtap_session unsigned perfmon; bool symtab; /* true: emit symbol table at translation time; false: let staprun do it. */ bool prologue_searching; + bool tapset_compile_coverage; // Cache data bool use_cache; @@ -122,6 +123,10 @@ struct systemtap_session std::vector<derived_probe*> probes; // see also *_probes groups below std::vector<embeddedcode*> embeds; std::map<std::string, statistic_decl> stat_decls; + // track things that are removed + std::vector<vardecl*> unused_globals; + std::vector<derived_probe*> unused_probes; // see also *_probes groups below + std::vector<functiondecl*> unused_functions; // XXX: vector<*> instead please? // Every probe in these groups must also appear in the diff --git a/staptree.cxx b/staptree.cxx index 08b2abae..3a50ac14 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -15,6 +15,7 @@ #include <typeinfo> #include <sstream> #include <cassert> +#include <vector> #include <algorithm> using namespace std; @@ -848,6 +849,13 @@ void probe::printsig (ostream& o) const } +void +probe::collect_derivation_chain (std::vector<derived_probe*> &probes_list) +{ + probes_list.push_back((derived_probe*)this); +} + + void probe_point::print (ostream& o) const { for (unsigned i=0; i<components.size(); i++) @@ -860,6 +868,23 @@ void probe_point::print (ostream& o) const } if (optional) o << "?"; + o << "{" << tok->location << "}\n"; +} + +string probe_point::str () +{ + ostringstream o; + for (unsigned i=0; i<components.size(); i++) + { + if (i>0) o << "."; + probe_point::component* c = components[i]; + o << c->functor; + if (c->arg) + o << "(" << *c->arg << ")"; + } + if (optional) + o << "?"; + return o.str(); } @@ -411,6 +411,7 @@ struct functiondecl: public symboldecl { std::vector<vardecl*> formal_args; std::vector<vardecl*> locals; + std::vector<vardecl*> unused_locals; statement* body; functiondecl (); void print (std::ostream& o) const; @@ -537,6 +538,7 @@ struct next_statement: public statement struct probe; +struct derived_probe; struct probe_alias; struct embeddedcode; struct stapfile @@ -570,6 +572,7 @@ struct probe_point void print (std::ostream& o) const; probe_point (); probe_point(std::vector<component*> const & comps,const token * t); + std::string str(); }; std::ostream& operator << (std::ostream& o, const probe_point& k); @@ -581,9 +584,11 @@ struct probe block* body; const token* tok; std::vector<vardecl*> locals; + std::vector<vardecl*> unused_locals; probe (); void print (std::ostream& o) const; virtual void printsig (std::ostream &o) const; + virtual void collect_derivation_chain (std::vector<derived_probe*> &probes_list); virtual probe* basest () { return this; } virtual ~probe() {} bool privileged; diff --git a/systemtap.spec.in b/systemtap.spec.in index ad58df0b..7f11b63a 100644 --- a/systemtap.spec.in +++ b/systemtap.spec.in @@ -39,6 +39,7 @@ Requires: kernel >= 2.6.9-11 BuildRequires: glib2-devel >= 2.0.0 # make check BuildRequires: dejagnu +BuildRequires: sqlite-devel Requires: glib2 >= 2.0.0 # Requires: kernel-devel # or is that kernel-smp-devel? kernel-hugemem-devel? @@ -46,6 +47,7 @@ Requires: gcc make # Suggest: kernel-debuginfo Requires: systemtap-runtime = %{version}-%{release} Requires: sudo +Requires: sqlite %if %{bundled_elfutils} Source1: elfutils-%{elfutils_version}.tar.gz |