]> sourceware.org Git - systemtap.git/commitdiff
PR13100: build tracepoint query modules separately, concurrently
authorFrank Ch. Eigler <fche@redhat.com>
Mon, 10 Oct 2011 09:08:22 +0000 (05:08 -0400)
committerFrank Ch. Eigler <fche@redhat.com>
Mon, 10 Oct 2011 09:11:45 +0000 (05:11 -0400)
* tapsets.cxx (tracepoint_extra_decls): Prepare for PR13155.
  (get_tracepoint_modules): Rewrite former get_tracepoint_module().
  (tracepoint_builder::init_dw): Don't even try to build all tracequery
  modules at once.
* buildrun.cxx (make_tracequeries): Replace make_tracequery().
  Run given compilation jobs in parallel.
* buildrun.h: Corresponding changes.
* hash.cxx (find_tracequery_hash): Clarify signature for single header.
* hash.h: Corresponding changes.

buildrun.cxx
buildrun.h
hash.cxx
hash.h
tapsets.cxx

index daa7b00c6e2b262a3c62ec32b86663ef299fcb07..c44ebbd429a3fa2582349ae912b3264f0958651a 100644 (file)
@@ -545,13 +545,16 @@ make_run_command (systemtap_session& s, const string& remotedir,
 }
 
 
-// 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);
@@ -560,59 +563,46 @@ make_tracequery(systemtap_session& s, string& name,
       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)
@@ -624,7 +614,7 @@ make_tracequery(systemtap_session& s, string& name,
   // 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;
 }
 
 
index 7e10f39ee09b79f0f864b42f05f22f9d0de047ad..e926c456242a55cb639aed204da3eb3bd27af566 100644 (file)
@@ -18,8 +18,7 @@ std::vector<std::string> make_run_command (systemtap_session& s,
                                            const std::string& remotedir="",
                                            const std::string& version=VERSION);
 
-int make_tracequery(systemtap_session& s, std::string& name,
-                    const std::vector<std::string>& headers);
+std::map<std::string,std::string> make_tracequeries(systemtap_session& s, const std::map<std::string,std::string>& contents);
 int make_typequery(systemtap_session& s, std::string& module);
 
 #endif // BUILDRUN_H
index 9284c0824da9127e01064c55ba6c02d059c516e6..479f2e8fac3feb83fed4bfdc9d1ce813289a4adc 100644 (file)
--- a/hash.cxx
+++ b/hash.cxx
@@ -316,13 +316,12 @@ find_stapconf_hash (systemtap_session& s)
 
 
 string
-find_tracequery_hash (systemtap_session& s, const vector<string>& headers)
+find_tracequery_hash (systemtap_session& s, const string& header)
 {
   hash h(get_base_hash(s));
 
-  // Add the tracepoint headers to the computed hash
-  for (size_t i = 0; i < headers.size(); ++i)
-    h.add_path("Headers ", headers[i]);
+  // Add the tracepoint header to the computed hash
+  h.add_path("Header ", header);
 
   // Add any custom kbuild flags
   for (unsigned i = 0; i < s.kbuildflags.size(); i++)
@@ -332,7 +331,7 @@ find_tracequery_hash (systemtap_session& s, const vector<string>& headers)
   string result, hashdir;
   h.result(result);
   if (!create_hashdir(s, result, hashdir))
-    return "";
+    return ""; // XXX: as opposed to throwing an exception?
 
   create_hash_log(string("tracequery_hash"), h.get_parms(), result,
                   hashdir + "/tracequery_" + result + "_hash.log");
diff --git a/hash.h b/hash.h
index d63c141847eea0788cdff999629156a6179edb78..c4c973220b1570e5400a3722b99101f5cdfc209f 100644 (file)
--- a/hash.h
+++ b/hash.h
@@ -9,7 +9,7 @@ class hash;
 void find_script_hash (systemtap_session& s, const std::string& script);
 void find_stapconf_hash (systemtap_session& s);
 std::string find_tracequery_hash (systemtap_session& s,
-                                  const std::vector<std::string>& headers);
+                                  const std::string& header);
 std::string find_typequery_hash (systemtap_session& s, const std::string& name);
 std::string find_uprobes_hash (systemtap_session& s);
 
index fe888616ddc1ff1636befbadcb7a83e6d40c80b3..1615f5ed53abd8f5fe34ce06793d041e3ab00a24 100644 (file)
@@ -8751,7 +8751,7 @@ tracepoint_derived_probe::print_dupe_stamp(ostream& o)
 }
 
 
-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
@@ -8803,7 +8803,7 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s)
 
   // 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";
 
@@ -9041,8 +9041,9 @@ struct tracepoint_builder: public derived_probe_builder
 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:
 
@@ -9066,9 +9067,15 @@ 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)
     {
@@ -9077,50 +9084,103 @@ tracepoint_builder::get_tracequery_module(systemtap_session& s,
         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);
+          }
+      }
 }
 
 
@@ -9205,21 +9265,8 @@ tracepoint_builder::init_dw(systemtap_session& s)
       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
This page took 0.04174 seconds and 5 git commands to generate.