blob: d2271be9cefc6729d21a9d69036dd0c0c5c7014d [file] [log] [blame]
mbligh15971eb2009-12-29 02:55:23 +00001import os, shutil, tempfile, logging
jadmanski043e1132008-11-19 17:10:32 +00002
mbligh15971eb2009-12-29 02:55:23 +00003import common
4from autotest_lib.client.common_lib import utils, error, profiler_manager
Prathmesh Prabhu8dacdb12017-09-01 12:12:18 -07005from autotest_lib.server import profiler, autotest, standalone_profiler
mbligh15971eb2009-12-29 02:55:23 +00006
7
Luis Lozano6b784d02015-07-21 00:24:17 +00008PROFILER_TMPDIR = '/tmp/profilers'
mbligh15971eb2009-12-29 02:55:23 +00009
10
11def get_profiler_results_dir(autodir):
12 """
13 Given the directory of the autotest client used to run a profiler,
14 return the remote path where profiler results will be stored.
15 """
mbligh9e44a452010-04-08 18:20:25 +000016 return os.path.join(autodir, 'results', 'default', 'profiler_sync',
mbligh15971eb2009-12-29 02:55:23 +000017 'profiling')
18
19
20def get_profiler_log_path(autodir):
21 """
22 Given the directory of a profiler client, find the client log path.
23 """
24 return os.path.join(autodir, 'results', 'default', 'debug', 'client.DEBUG')
jadmanski043e1132008-11-19 17:10:32 +000025
26
27class profilers(profiler_manager.profiler_manager):
jadmanskicb0e1612009-02-27 18:03:10 +000028 def __init__(self, job):
29 super(profilers, self).__init__(job)
30 self.add_log = {}
mbligh15971eb2009-12-29 02:55:23 +000031 self.start_delay = 0
32 # maps hostname to (host object, autotest.Autotest object, Autotest
33 # install dir), where the host object is the one created specifically
34 # for profiling
35 self.installed_hosts = {}
36 self.current_test = None
37
38
39 def set_start_delay(self, start_delay):
40 self.start_delay = start_delay
jadmanskicb0e1612009-02-27 18:03:10 +000041
42
jadmanski043e1132008-11-19 17:10:32 +000043 def load_profiler(self, profiler_name, args, dargs):
mbligh15971eb2009-12-29 02:55:23 +000044 newprofiler = profiler.profiler_proxy(profiler_name)
jadmanski043e1132008-11-19 17:10:32 +000045 newprofiler.initialize(*args, **dargs)
46 newprofiler.setup(*args, **dargs) # lazy setup is done client-side
47 return newprofiler
jadmanski4f909252008-12-01 20:47:10 +000048
49
jadmanskicb0e1612009-02-27 18:03:10 +000050 def add(self, profiler, *args, **dargs):
51 super(profilers, self).add(profiler, *args, **dargs)
52 self.add_log[profiler] = (args, dargs)
53
54
55 def delete(self, profiler):
56 super(profilers, self).delete(profiler)
mbligh30cf9dd2009-11-06 03:11:52 +000057 if profiler in self.add_log:
58 del self.add_log[profiler]
jadmanskicb0e1612009-02-27 18:03:10 +000059
60
mbligh15971eb2009-12-29 02:55:23 +000061 def _install_clients(self):
62 """
63 Install autotest on any current job hosts.
64 """
Prathmesh Prabhu8dacdb12017-09-01 12:12:18 -070065 in_use_hosts = dict()
mbligh15971eb2009-12-29 02:55:23 +000066 # find hosts in use but not used by us
67 for host in self.job.hosts:
Fang Denge3414332013-12-13 15:42:34 -080068 if host.hostname not in self.job.machines:
69 # job.hosts include all host instances created on the fly.
70 # We only care DUTs in job.machines which are
71 # piped in from autoserv -m option.
72 continue
mbligh15971eb2009-12-29 02:55:23 +000073 autodir = host.get_autodir()
74 if not (autodir and autodir.startswith(PROFILER_TMPDIR)):
Prathmesh Prabhu8dacdb12017-09-01 12:12:18 -070075 in_use_hosts[host.hostname] = host
76 logging.debug('Hosts currently in use: %s', set(in_use_hosts))
mbligh15971eb2009-12-29 02:55:23 +000077
78 # determine what valid host objects we already have installed
79 profiler_hosts = set()
80 for host, at, profiler_dir in self.installed_hosts.values():
81 if host.path_exists(profiler_dir):
82 profiler_hosts.add(host.hostname)
83 else:
84 # the profiler was wiped out somehow, drop this install
85 logging.warning('The profiler client on %s at %s was deleted',
86 host.hostname, profiler_dir)
mbligh15971eb2009-12-29 02:55:23 +000087 del self.installed_hosts[host.hostname]
88 logging.debug('Hosts with profiler clients already installed: %s',
89 profiler_hosts)
90
91 # install autotest on any new hosts in use
Prathmesh Prabhu8dacdb12017-09-01 12:12:18 -070092 for hostname in set(in_use_hosts) - profiler_hosts:
93 host = in_use_hosts[hostname]
mbligh15971eb2009-12-29 02:55:23 +000094 tmp_dir = host.get_tmp_dir(parent=PROFILER_TMPDIR)
95 at = autotest.Autotest(host)
96 at.install_no_autoserv(autodir=tmp_dir)
97 self.installed_hosts[host.hostname] = (host, at, tmp_dir)
98
99 # drop any installs from hosts no longer in job.hosts
Prathmesh Prabhu8dacdb12017-09-01 12:12:18 -0700100 for hostname in profiler_hosts - set(in_use_hosts):
101 del self.installed_hosts[hostname]
mbligh15971eb2009-12-29 02:55:23 +0000102
103
104 def _get_hosts(self, host=None):
105 """
106 Returns a list of (Host, Autotest, install directory) tuples for hosts
107 currently supported by this profiler. The returned Host object is always
108 the one created by this profiler, regardless of what's passed in. If
109 'host' is not None, all entries not matching that host object are
110 filtered out of the list.
111 """
112 if host is None:
113 return self.installed_hosts.values()
114 if host.hostname in self.installed_hosts:
115 return [self.installed_hosts[host.hostname]]
116 return []
117
118
119 def _get_local_profilers_dir(self, test, hostname):
mblighfc3da5b2010-01-06 18:37:22 +0000120 in_machine_dir = (
121 os.path.basename(test.job.resultdir) in test.job.machines)
122 if len(test.job.machines) > 1 and not in_machine_dir:
mbligh15971eb2009-12-29 02:55:23 +0000123 local_dir = os.path.join(test.profdir, hostname)
124 if not os.path.exists(local_dir):
125 os.makedirs(local_dir)
126 else:
127 local_dir = test.profdir
128
129 return local_dir
130
131
132 def _get_failure_logs(self, autodir, test, host):
133 """
134 Collect the client logs from a profiler run and put them in a
135 file named failure-*.log.
136 """
137 try:
138 fd, path = tempfile.mkstemp(suffix='.log', prefix='failure-',
139 dir=self._get_local_profilers_dir(test, host.hostname))
140 os.close(fd)
141 host.get_file(get_profiler_log_path(autodir), path)
mblighbe3238b2010-01-26 21:57:19 +0000142 # try to collect any partial profiler logs
143 self._get_profiler_logs(autodir, test, host)
mbligh15971eb2009-12-29 02:55:23 +0000144 except (error.AutotestError, error.AutoservError):
145 logging.exception('Profiler failure log collection failed')
146 # swallow the exception so that we don't override an existing
147 # exception being thrown
148
149
150 def _get_all_failure_logs(self, test, hosts):
151 for host, at, autodir in hosts:
152 self._get_failure_logs(autodir, test, host)
153
154
mblighbe3238b2010-01-26 21:57:19 +0000155 def _get_profiler_logs(self, autodir, test, host):
156 results_dir = get_profiler_results_dir(autodir)
157 local_dir = self._get_local_profilers_dir(test, host.hostname)
158
159 self.job.remove_client_log(host.hostname, results_dir, local_dir)
160
161 tempdir = tempfile.mkdtemp(dir=self.job.tmpdir)
162 try:
163 host.get_file(results_dir + '/', tempdir)
164 except error.AutoservRunError:
165 pass # no files to pull back, nothing we can do
166 utils.merge_trees(tempdir, local_dir)
167 shutil.rmtree(tempdir, ignore_errors=True)
168
169
mbligh15971eb2009-12-29 02:55:23 +0000170 def _run_clients(self, test, hosts):
171 """
172 We initialize the profilers just before start because only then we
173 know all the hosts involved.
174 """
175
176 hostnames = [host_info[0].hostname for host_info in hosts]
177 profilers_args = [(p.name, p.args, p.dargs)
178 for p in self.list]
179
180 for host, at, autodir in hosts:
181 control_script = standalone_profiler.generate_test(hostnames,
182 host.hostname,
183 profilers_args,
184 180, None)
185 try:
186 at.run(control_script, background=True)
187 except Exception:
188 self._get_failure_logs(autodir, test, host)
189 raise
190
191 remote_results_dir = get_profiler_results_dir(autodir)
192 local_results_dir = self._get_local_profilers_dir(test,
193 host.hostname)
194 self.job.add_client_log(host.hostname, remote_results_dir,
195 local_results_dir)
196
197 try:
198 # wait for the profilers to be added
199 standalone_profiler.wait_for_profilers(hostnames)
200 except Exception:
201 self._get_all_failure_logs(test, hosts)
202 raise
203
204
205 def before_start(self, test, host=None):
206 # create host objects and install the needed clients
207 # so later in start() we don't spend too much time
208 self._install_clients()
209 self._run_clients(test, self._get_hosts(host))
210
211
212 def start(self, test, host=None):
213 hosts = self._get_hosts(host)
214
215 # wait for the profilers to start
216 hostnames = [host_info[0].hostname for host_info in hosts]
217 try:
218 standalone_profiler.start_profilers(hostnames)
219 except Exception:
220 self._get_all_failure_logs(test, hosts)
221 raise
222
223 self.current_test = test
224
225
226 def stop(self, test):
227 assert self.current_test == test
228
229 hosts = self._get_hosts()
230 # wait for the profilers to stop
231 hostnames = [host_info[0].hostname for host_info in hosts]
232 try:
233 standalone_profiler.stop_profilers(hostnames)
234 except Exception:
235 self._get_all_failure_logs(test, hosts)
236 raise
237
238
239 def report(self, test, host=None):
240 assert self.current_test == test
241
242 hosts = self._get_hosts(host)
243 # when running on specific hosts we cannot wait for the other
244 # hosts to sync with us
245 if not host:
246 hostnames = [host_info[0].hostname for host_info in hosts]
247 try:
248 standalone_profiler.finish_profilers(hostnames)
249 except Exception:
250 self._get_all_failure_logs(test, hosts)
251 raise
252
253 # pull back all the results
254 for host, at, autodir in hosts:
mblighbe3238b2010-01-26 21:57:19 +0000255 self._get_profiler_logs(autodir, test, host)
mbligh15971eb2009-12-29 02:55:23 +0000256
257
jadmanski4f909252008-12-01 20:47:10 +0000258 def handle_reboot(self, host):
mbligh15971eb2009-12-29 02:55:23 +0000259 if self.current_test:
260 test = self.current_test
261 for profiler in self.list:
262 if not profiler.supports_reboot:
263 msg = 'profiler %s does not support rebooting during tests'
264 msg %= profiler.name
265 self.job.record('WARN', os.path.basename(test.outputdir),
266 None, msg)
267
268 self.report(test, host)
269 self.before_start(test, host)
270 self.start(test, host)