1"""
2Trace kernel events with Linux Tracing Toolkit (lttng).
3You need to install the lttng patched kernel in order to use the profiler.
4
5Examples:
6    job.profilers.add('lttng', tracepoints = None): enable all trace points.
7    job.profilers.add('lttng', tracepoints = []): disable all trace points.
8    job.profilers.add('lttng', tracepoints = ['kernel_arch_syscall_entry',
9                                              'kernel_arch_syscall_exit'])
10                               will only trace syscall events.
11Take a look at /proc/ltt for the list of the tracing events currently
12supported by lttng and their output formats.
13
14To view the collected traces, copy results/your-test/profiler/lttng
15to a machine that has Linux Tracing Toolkit Viewer (lttv) installed:
16    test$ scp -r results/your-test/profiler/lttng user@localmachine:/home/tmp/
17Then you can examine the traces either in text mode or in GUI:
18    localmachine$ lttv -m textDump -t /home/tmp/lttng
19or
20    localmachine$ lttv-gui -t /home/tmp/lttng &
21"""
22
23import os, shutil, time
24from autotest_lib.client.bin import utils, profiler
25from autotest_lib.client.common_lib import error
26
27class lttng(profiler.profiler):
28    version = 1
29
30    # http://ltt.polymtl.ca/lttng/ltt-control-0.51-12082008.tar.gz
31    def setup(self, tarball='ltt-control-0.51-12082008.tar.gz', **dargs):
32        self.tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir)
33        utils.extract_tarball_to_dir(self.tarball, self.srcdir)
34        os.chdir(self.srcdir)
35
36        utils.configure()
37        utils.make()
38
39
40    # tracepoints: list of trace points to enable
41    # outputsize: size limit for lttng output file. -1: no limit.
42    def initialize(self, outputsize=1048576, tracepoints=None, **dargs):
43        self.job.require_gcc()
44
45        self.tracepoints = tracepoints
46        self.ltt_bindir = os.path.join(self.srcdir, 'lttctl')
47        self.lttctl = os.path.join(self.ltt_bindir, 'lttctl')
48        self.lttd = os.path.join(self.srcdir, 'lttd', 'lttd')
49        self.armall = os.path.join(self.ltt_bindir, 'ltt-armall')
50        self.disarmall = os.path.join(self.ltt_bindir, 'ltt-disarmall')
51        self.mountpoint = '/mnt/debugfs'
52        self.outputsize = outputsize
53
54        os.putenv('LTT_DAEMON', self.lttd)
55
56        if not os.path.exists(self.mountpoint):
57            os.mkdir(self.mountpoint)
58
59        utils.system('mount -t debugfs debugfs ' + self.mountpoint,
60                                                            ignore_status=True)
61        utils.system('modprobe ltt-control')
62        utils.system('modprobe ltt-statedump')
63        # clean up from any tracing we left running
64        utils.system(self.lttctl + ' -n test -R', ignore_status=True)
65        utils.system(self.disarmall, ignore_status=True)
66
67        if tracepoints is None:
68            utils.system(self.armall, ignore_status=True)
69        else:
70            for tracepoint in self.tracepoints:
71                if tracepoint in ('list_process_state',
72                                  'user_generic_thread_brand', 'fs_exec',
73                                  'kernel_process_fork', 'kernel_process_free',
74                                  'kernel_process_exit',
75                                  'kernel_arch_kthread_create',
76                                  'list_statedump_end', 'list_vm_map'):
77                    channel = 'processes'
78                elif tracepoint in ('list_interrupt',
79                                    'statedump_idt_table',
80                                    'statedump_sys_call_table'):
81                    channel = 'interrupts'
82                elif tracepoint in ('list_network_ipv4_interface',
83                                    'list_network_ip_interface'):
84                    channel = 'network'
85                elif tracepoint in ('kernel_module_load', 'kernel_module_free'):
86                    channel = 'modules'
87                else:
88                    channel = ''
89                print 'Connecting ' + tracepoint
90                utils.write_one_line('/proc/ltt', 'connect ' + tracepoint
91                                     + ' default dynamic ' + channel)
92
93    def start(self, test):
94        self.output = os.path.join(test.profdir, 'lttng')
95        utils.system('%s -n test -d -l %s/ltt -t %s' %
96                                  (self.lttctl, self.mountpoint, self.output))
97
98
99    def stop(self, test):
100        utils.system(self.lttctl + ' -n test -R')
101        time.sleep(10)
102        if self.outputsize != -1:
103            # truncate lttng output file to the specified limit
104            for filename in os.listdir(self.output):
105                file_path = os.path.join(self.output, filename)
106                if os.path.isdir(file_path):
107                    continue
108                size = os.stat(file_path)[6] # grab file size
109                if size > self.outputsize:
110                    f = open(file_path, 'r+')
111                    f.truncate(self.outputsize)
112                    f.close()
113        tarball = os.path.join(test.profdir, 'lttng.tar.bz2')
114        utils.system("tar -cvjf %s -C %s %s" % (tarball, test.profdir, 'lttng'))
115        utils.system('rm -rf ' + self.output)
116