OLD | NEW |
(Empty) | |
| 1 """ |
| 2 Function tracer profiler for autotest. |
| 3 |
| 4 @author: David Sharp (dhsharp@google.com) |
| 5 """ |
| 6 import logging, os, signal, time |
| 7 from autotest_lib.client.bin import profiler, utils |
| 8 |
| 9 |
| 10 class ftrace(profiler.profiler): |
| 11 """ |
| 12 ftrace profiler for autotest. It builds ftrace from souce and runs |
| 13 trace-cmd with configurable parameters. |
| 14 |
| 15 @see: git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git |
| 16 """ |
| 17 version = 1 |
| 18 |
| 19 mountpoint = '/sys/kernel/debug' |
| 20 tracing_dir = os.path.join(mountpoint, 'tracing') |
| 21 |
| 22 @staticmethod |
| 23 def join_command(cmd): |
| 24 """ |
| 25 Shell escape the command for BgJob. grmbl. |
| 26 |
| 27 @param cmd: Command list. |
| 28 """ |
| 29 result = [] |
| 30 for arg in cmd: |
| 31 arg = '"%s"' % utils.sh_escape(arg) |
| 32 result += [arg] |
| 33 return ' '.join(result) |
| 34 |
| 35 |
| 36 def setup(self, tarball='trace-cmd.tar.bz2', **kwargs): |
| 37 """ |
| 38 Build and install trace-cmd from source. |
| 39 |
| 40 The tarball was obtained by checking the git repo at 09-14-2010, |
| 41 removing the Documentation and the .git folders, and compressing |
| 42 it. |
| 43 |
| 44 @param tarball: Path to trace-cmd tarball. |
| 45 @param **kwargs: Dictionary with additional parameters. |
| 46 """ |
| 47 self.tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir) |
| 48 utils.extract_tarball_to_dir(self.tarball, self.srcdir) |
| 49 os.chdir(self.srcdir) |
| 50 utils.make("prefix='%s'" % self.builddir) |
| 51 utils.make("prefix='%s' install" % self.builddir) |
| 52 |
| 53 |
| 54 def initialize(self, tracepoints, buffer_size_kb=1408, **kwargs): |
| 55 """ |
| 56 Initialize ftrace profiler. |
| 57 |
| 58 @param tracepoints: List containing a mix of tracpoint names and |
| 59 (tracepoint name, filter) tuples. Tracepoint names are as |
| 60 accepted by trace-cmd -e, eg "syscalls", or |
| 61 "syscalls:sys_enter_read". Filters are as accepted by |
| 62 trace-cmd -f, eg "((sig >= 10 && sig < 15) || sig == 17)" |
| 63 @param buffer_size_kb: Set the size of the ring buffer (per cpu). |
| 64 """ |
| 65 self.job.require_gcc() |
| 66 self.trace_cmd_args = ['-b', str(buffer_size_kb)] |
| 67 for tracepoint in tracepoints: |
| 68 if isinstance(tracepoint, tuple): |
| 69 tracepoint, event_filter = tracepoint |
| 70 else: |
| 71 event_filter = None |
| 72 self.trace_cmd_args += ['-e', tracepoint] |
| 73 if event_filter: |
| 74 self.trace_cmd_args += ['-f', event_filter] |
| 75 |
| 76 self.builddir = os.path.join(self.bindir, 'build') |
| 77 if not os.path.isdir(self.builddir): |
| 78 os.makedirs(self.builddir) |
| 79 self.trace_cmd = os.path.join(self.builddir, 'bin', 'trace-cmd') |
| 80 |
| 81 |
| 82 def start(self, test): |
| 83 """ |
| 84 Start ftrace profiler |
| 85 |
| 86 @param test: Autotest test in which the profiler will operate on. |
| 87 """ |
| 88 # Make sure debugfs is mounted and tracing disabled. |
| 89 utils.system('%s reset' % self.trace_cmd) |
| 90 |
| 91 output_dir = os.path.join(test.profdir, 'ftrace') |
| 92 if not os.path.isdir(output_dir): |
| 93 os.makedirs(output_dir) |
| 94 self.output = os.path.join(output_dir, 'trace.dat') |
| 95 cmd = [self.trace_cmd, 'record', '-o', self.output] |
| 96 cmd += self.trace_cmd_args |
| 97 self.record_job = utils.BgJob(self.join_command(cmd), |
| 98 stderr_tee=utils.TEE_TO_LOGS) |
| 99 |
| 100 # Wait for tracing to be enabled. If trace-cmd dies before enabling |
| 101 # tracing, then there was a problem. |
| 102 tracing_on = os.path.join(self.tracing_dir, 'tracing_on') |
| 103 while (self.record_job.sp.poll() is None and |
| 104 utils.read_file(tracing_on).strip() != '1'): |
| 105 time.sleep(0.1) |
| 106 if self.record_job.sp.poll() is not None: |
| 107 utils.join_bg_jobs([self.record_job]) |
| 108 raise error.CmdError(self.record_job.command, |
| 109 self.record_job.sp.returncode, |
| 110 'trace-cmd exited early.') |
| 111 |
| 112 def stop(self, test): |
| 113 """ |
| 114 Stop ftrace profiler. |
| 115 |
| 116 @param test: Autotest test in which the profiler will operate on. |
| 117 """ |
| 118 os.kill(self.record_job.sp.pid, signal.SIGINT) |
| 119 utils.join_bg_jobs([self.record_job]) |
| 120 # shrink the buffer to free memory. |
| 121 utils.system('%s reset -b 1' % self.trace_cmd) |
| 122 |
| 123 #compress output |
| 124 utils.system('bzip2 %s' % self.output) |
| 125 compressed_output = self.output + '.bz2' |
| 126 # if the compressed trace file is large (10MB), just delete it. |
| 127 compressed_output_size = os.path.getsize(compressed_output) |
| 128 if compressed_output_size > 10*1024*1024: |
| 129 logging.warn('Deleting large trace file %s (%d bytes)', |
| 130 compressed_output, compressed_output_size) |
| 131 os.remove(compressed_output) |
| 132 # remove per-cpu files in case trace-cmd died. |
| 133 utils.system('rm -f %s.cpu*' % self.output) |
OLD | NEW |