This depends on Martin's "run autoserv without a results dir" patch
to be applied cleanly.
A rather large refactoring and stubbing change working towards
client-side profilers from the server side. This makes a few major
changes:
- refactors almost all of client/bin/profilers.py into a common lib
profiler_manager class; except for the code for actually loading
a profiler object, all of that code is already completely generic
- add a server-side profiler_proxy class that will act as a proxy
on the server for using a client-side profiler, this doesn't
actually do anything useful right now but it basically just a
stub for later changes
- add a server-side profiler_manager implementation that creates a
profiler_proxy class instead of actually loading a real profiler
The intended changes still in the pipeline that will build on this are:
- add code to the profiler_proxy for actually making sure the
profiler is set up and installed on the remote host(s)
- add a mechanism for client-side profilers to deal with reboots
Risk: Medium
Visibility: Adds a bunch of stubs that don't actually do anything yet
but will do things soon.
Signed-off-by: John Admanski <[email protected]>
git-svn-id: http://test.kernel.org/svn/autotest/trunk@2447 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/server/profiler.py b/server/profiler.py
new file mode 100644
index 0000000..a23c655
--- /dev/null
+++ b/server/profiler.py
@@ -0,0 +1,84 @@
+import itertools
+from autotest_lib.server import autotest
+
+
+
+def get_unpassable_types(arg):
+ """ Given an argument, returns a set of types contained in arg that are
+ unpassable. If arg is an atomic type (e.g. int) it either returns an
+ empty set (if the type is passable) or a singleton of the type (if the
+ type is not passable). """
+ if isinstance(arg, (basestring, int, long)):
+ return set()
+ elif isinstance(arg, (list, tuple, set, frozenset, dict)):
+ if isinstance(arg, dict):
+ # keys and values must both be passable
+ parts = itertools.chain(arg.iterkeys(), arg.itervalues())
+ else:
+ # for all other containers we just iterate
+ parts = iter(arg)
+ types = set()
+ for part in parts:
+ types |= get_unpassable_types(arg)
+ return types
+ else:
+ return set([type(arg)])
+
+
+def validate_args(args):
+ """ Validates arguments. Lists and dictionaries are valid argument types,
+ so you can pass *args and **dargs in directly, rather than having to
+ iterate over them yourself. """
+ unpassable_types = get_unpassable_types(args)
+ if unpassable_types:
+ msg = "arguments of type '%s' cannot be passed to remote profilers"
+ msg %= ", ".join(t.__name__ for t in unpassable_types)
+ raise TypeError(msg)
+
+
+class profiler_proxy(object):
+ """ This is a server-side class that acts as a proxy to a real client-side
+ profiler class."""
+
+ def __init__(self, job, profiler_name):
+ self.job = job
+ self.name = profiler_name
+ self.installed_hosts = {}
+
+
+ def _install(self):
+ """ Install autotest on any current job hosts. """
+ current_job_hosts = self.job.hosts
+ current_profiler_hosts = set(self.installed_hosts.keys())
+ # install autotest on any new hosts in job.hosts
+ for host in current_job_hosts - current_profiler_hosts:
+ tmp_dir = host.get_tmp_dir(parent="/tmp/profilers")
+ at = autotest.Autotest(host)
+ at.install(autodir=tmp_dir)
+ self.installed_hosts[host] = at
+ # drop any installs from hosts no longer in job.hosts
+ for host in current_profiler_hosts - current_job_hosts:
+ del self.installed_hosts[host]
+
+
+ def setup(self, *args, **dargs):
+ validate_args(args)
+ validate_args(dargs)
+ self._install()
+
+
+ def initialize(self, *args, **dargs):
+ validate_args(args)
+ validate_args(dargs)
+
+
+ def start(self, test):
+ pass
+
+
+ def stop(self, test):
+ pass
+
+
+ def report(self, test):
+ pass