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