1# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5
6import logging
7from autotest_lib.client.bin import test, utils
8
9
10class kernel_Lmbench(test.test):
11    """Run some benchmarks from the lmbench3 suite.
12
13    lmbench is a series of micro benchmarks intended to measure basic operating
14    system and hardware system metrics.
15
16    For further details about lmbench refer to:
17    http://lmbench.sourceforge.net/man/lmbench.8.html
18
19    This test is copied from from client/tests to avoid depending on make and
20    perl. Here we can also tune the individual benchmarks to be more
21    deterministic using taskset, nice, etc.
22
23    Example benchmark runs and outputs on a Lumpy device:
24    ./lat_pagefault -N 100 -W 10000 /usr/local/zeros 2>&1
25    Pagefaults on /usr/local/zeros: 1.5215 microseconds
26
27    ./lat_syscall -N 100 -W 10000 null 2>&1
28    Simple syscall: 0.1052 microseconds
29
30    ./lat_syscall -N 100 -W 10000 read /usr/local/zeros 2>&1
31    Simple read: 0.2422 microseconds
32
33    ./lat_syscall -N 100 -W 10000 write /usr/local/zeros 2>&1
34    Simple write: 0.2036 microseconds
35
36    ./lat_proc -N 100 -W 10000 fork 2>&1
37    Process fork+exit: 250.9048 microseconds
38
39    ./lat_proc -N 100 -W 10000 exec 2>&1
40    Process fork+execve: 270.8000 microseconds
41
42    ./lat_mmap -N 100 -W 10000 128M /usr/local/zeros 2>&1
43    134.217728 1644
44
45    ./lat_mmap -P 2 -W 10000 128M /usr/local/zeros 2>&1
46    134.217728 2932
47
48    ./lat_pipe -N 100 -W 10000 2>&1
49    Pipe latency: 14.3242 microseconds
50
51    taskset 0x1 nice -20 ./lat_ctx -s 0 -W 10000  8 2>&1
52    "size=0k ovr=1.09
53    8 1.80
54    """
55
56    version = 1
57
58    def _run_benchmarks(self):
59        """Run the benchmarks.
60
61        For details and output format refer to individual benchmark man pages:
62        http://lmbench.sourceforge.net/man/
63
64        To improve determinism, we sometimes use taskset to pin to a CPU and
65        nice.
66        """
67
68        benchmarks = [
69            ('lat_pagefault',
70             'lat_pagefault -N %(N)d -W %(W)d %(fname)s 2>&1'),
71            ('lat_syscall_null',
72             'lat_syscall -N %(N)d -W %(W)d null 2>&1'),
73            ('lat_syscall_read',
74             'lat_syscall -N %(N)d -W %(W)d read %(fname)s 2>&1'),
75            ('lat_syscall_write',
76             'lat_syscall -N %(N)d -W %(W)d write %(fname)s 2>&1'),
77            ('lat_proc_fork',
78             'lat_proc -N %(N)d -W %(W)d fork 2>&1'),
79            ('lat_proc_exec',
80             'lat_proc -N %(N)d -W %(W)d exec 2>&1'),
81            ('lat_mmap',
82             ('lat_mmap -N %(N)d -W %(W)d '
83              '%(fsize)dM %(fname)s 2>&1')),
84            ('lat_mmap_P2',
85             'lat_mmap -P 2 -W %(W)d %(fsize)dM %(fname)s 2>&1'),
86            ('lat_pipe',
87             'lat_pipe -N %(N)d -W %(W)d 2>&1'),
88            ('lat_ctx_s0',
89             ('taskset 0x1 nice -20 '
90              'lat_ctx -s 0 -W %(W)d  %(procs)d 2>&1'))
91        ]
92
93        keyvals = {}
94
95        # Create a file with <fsize> MB of zeros in /usr/local
96        cmd = 'dd if=/dev/zero of=%(fname)s bs=1M count=%(fsize)d'
97        cmd = cmd % self.lmparams
98        utils.system(cmd)
99
100        for (bm, cmd) in benchmarks:
101            cmd = cmd % self.lmparams
102            logging.info('Running: %s, cmd: %s', bm, cmd)
103            out = utils.system_output(cmd)
104            logging.info('Output: %s', out)
105
106            # See class doc string for output examples
107            lst = out.split()
108            idx = -2
109            if '_mmap' in bm or '_ctx' in bm:
110                idx = -1
111            useconds = float(lst[idx])
112            keyvals['us_' + bm] = useconds
113
114        self.lmkeyvals.update(keyvals)
115
116
117    def initialize(self):
118        self.job.require_gcc()
119        self.lmkeyvals = {}
120
121        # Common parameters for the benchmarks. More details here:
122        # http://lmbench.sourceforge.net/man/lmbench.8.html
123        # N - number of repetitions
124        # P - parallelism
125        # W - warmup time in microseconds
126        # fname - file to operate on
127        # fsize - size of the above file in MB
128        # procs - number of processes for context switch benchmark - lat_ctx
129        self.lmparams = {
130            'N':100,
131            'P':2,
132            'fname':'/usr/local/zeros',
133            'fsize':128,
134            'W':10000,
135            'procs':8}
136
137        # Write out the params as kevals now to keep them even if test fails
138        param_kvals = [('param_%s' % p,v) for (p,v) in self.lmparams.items()]
139        self.write_perf_keyval(dict(param_kvals))
140
141    def run_once(self):
142        self._run_benchmarks()
143        self.write_perf_keyval(self.lmkeyvals)
144