}
-// Build a tiny kernel module to query tracepoints
-int
-make_tracequery(systemtap_session& s, string& name,
- const vector<string>& decls)
+// Build tiny kernel modules to query tracepoints.
+// Given a (header-file -> test-contents) map, compile them ASAP, and return
+// a (header-file -> ko-filename) map.
+
+map<string,string>
+make_tracequeries(systemtap_session& s, const map<string,string>& contents)
{
static unsigned tick = 0;
string basename("tracequery_kmod_" + lex_cast(++tick));
+ map<string,string> kos;
// create a subdirectory for the module
string dir(s.tmpdir + "/" + basename);
if (! s.suppress_warnings)
cerr << _("Warning: failed to create directory for querying tracepoints.") << endl;
s.set_try_server ();
- return 1;
+ return kos;
}
- name = dir + "/" + basename + ".ko";
-
// create a simple Makefile
string makefile(dir + "/Makefile");
ofstream omf(makefile.c_str());
// force debuginfo generation, and relax implicit functions
omf << "EXTRA_CFLAGS := -g -Wno-implicit-function-declaration" << (s.omit_werror ? "" : " -Werror") << endl;
- if (s.kernel_source_tree != "")
- omf << "EXTRA_CFLAGS += -I" + s.kernel_source_tree << endl;
- omf << "obj-m := " + basename + ".o" << endl;
-
// RHBZ 655231: later rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules
omf << "CONFIG_MODULE_SIG := n" << endl;
- omf.close();
+ if (s.kernel_source_tree != "")
+ omf << "EXTRA_CFLAGS += -I" + s.kernel_source_tree << endl;
- // create our source file
- string source(dir + "/" + basename + ".c");
- ofstream osrc(source.c_str());
- osrc << "#ifdef CONFIG_TRACEPOINTS" << endl;
- osrc << "#include <linux/tracepoint.h>" << endl;
-
- // override DECLARE_TRACE to synthesize probe functions for us
- osrc << "#undef DECLARE_TRACE" << endl;
- osrc << "#define DECLARE_TRACE(name, proto, args) \\" << endl;
- osrc << " void stapprobe_##name(proto) {}" << endl;
-
- // 2.6.35 added the NOARGS variant, but it's the same for us
- osrc << "#undef DECLARE_TRACE_NOARGS" << endl;
- osrc << "#define DECLARE_TRACE_NOARGS(name) \\" << endl;
- osrc << " DECLARE_TRACE(name, void, )" << endl;
-
- // older tracepoints used DEFINE_TRACE, so redirect that too
- osrc << "#undef DEFINE_TRACE" << endl;
- osrc << "#define DEFINE_TRACE(name, proto, args) \\" << endl;
- osrc << " DECLARE_TRACE(name, TPPROTO(proto), TPARGS(args))" << endl;
-
- // add the specified decls/#includes
- for (unsigned z=0; z<decls.size(); z++)
- osrc << "#undef TRACE_INCLUDE_FILE\n"
- << "#undef TRACE_INCLUDE_PATH\n"
- << decls[z] << "\n";
-
- // finish up the module source
- osrc << "#endif /* CONFIG_TRACEPOINTS */" << endl;
- osrc.close();
+ omf << "obj-m := " << endl;
+ // write out each header-specific source file into a separate file
+ for (map<string,string>::const_iterator it = contents.begin(); it != contents.end(); it++)
+ {
+ string sbasename = basename + "_" + lex_cast(++tick); // suffixed
+
+ // write out source code
+ string srcname = dir + "/" + sbasename + ".c";
+ string src = it->second;
+ ofstream osrc(srcname.c_str());
+ osrc << src;
+ osrc.close();
+
+ // arrange to build it
+ omf << "obj-m += " + sbasename + ".o" << endl; // NB: without <dir> prefix
+ kos[it->first] = dir + "/" + sbasename + ".ko";
+ }
+ omf.close();
// make the module
vector<string> make_cmd = make_make_cmd(s, dir);
make_cmd.push_back ("-i"); // ignore errors, give rc 0 even in case of tracepoint header nits
+ // parallelize the make job, since we have lots of little modules to build
+ long smp = sysconf(_SC_NPROCESSORS_ONLN);
+ if (smp >= 1)
+ make_cmd.push_back("-j" + lex_cast(smp+1));
bool quiet = (s.verbose < 4);
int rc = run_make_cmd(s, make_cmd, quiet, quiet);
if (rc)
// other useful diagnostic. -vvvv would let a user see what's up,
// but the user can't fix the problem even with that.
- return rc;
+ return kos;
}
}
-static vector<string> tracepoint_extra_decls (systemtap_session& s)
+static vector<string> tracepoint_extra_decls (systemtap_session& s, const string& header)
{
vector<string> they_live;
// PR 9993
// PR9993: Add extra headers to work around undeclared types in individual
// include/trace/foo.h files
- const vector<string>& extra_decls = tracepoint_extra_decls (s);
+ const vector<string>& extra_decls = tracepoint_extra_decls (s, "XXXXXXX");
for (unsigned z=0; z<extra_decls.size(); z++)
s.op->newline() << extra_decls[z] << "\n";
private:
dwflpp *dw;
bool init_dw(systemtap_session& s);
- string get_tracequery_module(systemtap_session& s,
- const vector<string>& headers);
+ void get_tracequery_modules(systemtap_session& s,
+ const vector<string>& headers,
+ vector<string>& modules);
public:
};
-string
-tracepoint_builder::get_tracequery_module(systemtap_session& s,
- const vector<string>& headers)
+
+// Create (or cache) one or more tracequery .ko modules, based upon the
+// tracepoint-related header files given. Return the generated or cached
+// modules[].
+
+void
+tracepoint_builder::get_tracequery_modules(systemtap_session& s,
+ const vector<string>& headers,
+ vector<string>& modules)
{
if (s.verbose > 2)
{
clog << " " << headers[i] << endl;
}
- string tracequery_path;
- if (s.use_cache)
- {
- // see if the cached module exists
- tracequery_path = find_tracequery_hash(s, headers);
- if (!tracequery_path.empty() && !s.poison_cache)
- {
- int fd = open(tracequery_path.c_str(), O_RDONLY);
- if (fd != -1)
- {
- if (s.verbose > 2)
- clog << _F("Pass 2: using cached %s", tracequery_path.c_str()) << endl;
- close(fd);
- return tracequery_path;
- }
- }
- }
+ map<string,string> headers_cacheko; // header name -> cache/.../tracequery_hash.ko file name
+ // Map the headers to cache .ko names. Note that this has side-effects of
+ // creating the $SYSTEMTAP_DIR/.cache/XX/... directory and the hash-log file,
+ // so we prefer not to repeat this.
+ vector<string> uncached_headers;
+ for (size_t i=0; i<headers.size(); i++)
+ headers_cacheko[headers[i]] = find_tracequery_hash(s, headers[i]);
+
+ // They may be in the cache already.
+ if (s.use_cache && !s.poison_cache)
+ for (size_t i=0; i<headers.size(); i++)
+ {
+ // see if the cached module exists
+ string tracequery_path = headers_cacheko[headers[i]];
+ if (!tracequery_path.empty() && file_exists(tracequery_path))
+ {
+ if (s.verbose > 2)
+ clog << _F("Pass 2: using cached %s", tracequery_path.c_str()) << endl;
+ modules.push_back (tracequery_path);
+ }
+ else
+ uncached_headers.push_back(headers[i]);
+ }
+ else
+ uncached_headers = headers;
- // no cached module, time to make it
+ // If we have nothing left to search for, quit
+ if (uncached_headers.empty()) return;
- // PR9993: Add extra headers to work around undeclared types in individual
- // include/trace/foo.h files
- vector<string> short_decls = tracepoint_extra_decls(s);
+ map<string,string> headers_tracequery_src; // header -> C-source code mapping
- // add each requested tracepoint header
- for (size_t i = 0; i < headers.size(); ++i)
+ // We could query several subsets of headers[] to make this go
+ // faster, but let's KISS and do one at a time.
+ for (size_t i=0; i<uncached_headers.size(); i++)
{
- const string &header = headers[i];
+ const string& header = uncached_headers[i];
+
+ // create a tracequery source file
+ ostringstream osrc;
+
+ // PR9993: Add extra headers to work around undeclared types in individual
+ // include/trace/foo.h files
+ vector<string> short_decls = tracepoint_extra_decls(s, header);
+
+ // add each requested tracepoint header
size_t root_pos = header.rfind("include/");
short_decls.push_back(string("#include <") +
((root_pos != string::npos) ? header.substr(root_pos + 8) : header) +
string(">"));
- }
- string tracequery_ko;
- int rc = make_tracequery(s, tracequery_ko, short_decls);
- if (rc != 0 || ! file_exists(tracequery_ko))
- tracequery_ko = "/dev/null";
+ osrc << "#ifdef CONFIG_TRACEPOINTS" << endl;
+ osrc << "#include <linux/tracepoint.h>" << endl;
+
+ // override DECLARE_TRACE to synthesize probe functions for us
+ osrc << "#undef DECLARE_TRACE" << endl;
+ osrc << "#define DECLARE_TRACE(name, proto, args) \\" << endl;
+ osrc << " void stapprobe_##name(proto) {}" << endl;
+
+ // 2.6.35 added the NOARGS variant, but it's the same for us
+ osrc << "#undef DECLARE_TRACE_NOARGS" << endl;
+ osrc << "#define DECLARE_TRACE_NOARGS(name) \\" << endl;
+ osrc << " DECLARE_TRACE(name, void, )" << endl;
+
+ // older tracepoints used DEFINE_TRACE, so redirect that too
+ osrc << "#undef DEFINE_TRACE" << endl;
+ osrc << "#define DEFINE_TRACE(name, proto, args) \\" << endl;
+ osrc << " DECLARE_TRACE(name, TPPROTO(proto), TPARGS(args))" << endl;
+
+ // add the specified decls/#includes
+ for (unsigned z=0; z<short_decls.size(); z++)
+ osrc << "#undef TRACE_INCLUDE_FILE\n"
+ << "#undef TRACE_INCLUDE_PATH\n"
+ << short_decls[z] << "\n";
+
+ // finish up the module source
+ osrc << "#endif /* CONFIG_TRACEPOINTS */" << endl;
- // try to save tracequery in the cache
- if (s.use_cache)
- copy_file(tracequery_ko, tracequery_path, s.verbose > 2);
+ // save the source file away
+ headers_tracequery_src[header] = osrc.str();
+ }
+
+ // now build them all together
+ map<string,string> tracequery_kos = make_tracequeries(s, headers_tracequery_src);
- return tracequery_ko;
+ // now plop them into the cache
+ if (s.use_cache)
+ for (size_t i=0; i<uncached_headers.size(); i++)
+ {
+ const string& header = uncached_headers[i];
+ const string& tracequery_ko = tracequery_kos[header];
+ if (tracequery_ko !="" && file_exists(tracequery_ko))
+ {
+ const string& tracequery_path = headers_cacheko[header];
+ copy_file(tracequery_ko, tracequery_path, s.verbose > 2);
+ modules.push_back (tracequery_path);
+ }
+ }
}
globfree(&trace_glob);
}
- // First attempt to do all system headers in one go
- string tracequery_path = get_tracequery_module(s, system_headers);
- // NB: An empty tracequery means that the header didn't compile correctly
- if (get_file_size(tracequery_path))
- tracequery_modules.push_back(tracequery_path);
- else
- // Otherwise try to do them one at a time (PR10424)
- for (size_t i = 0; i < system_headers.size(); ++i)
- {
- if (pending_interrupts) return false;
- vector<string> one_header(1, system_headers[i]);
- tracequery_path = get_tracequery_module(s, one_header);
- if (get_file_size(tracequery_path))
- tracequery_modules.push_back(tracequery_path);
- }
+ // Build tracequery modules
+ get_tracequery_modules(s, system_headers, tracequery_modules);
// TODO: consider other sources of tracepoint headers too, like from
// a command-line parameter or some environment or .systemtaprc