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