1import os, re
2from autotest_lib.client.bin import test, utils
3import postprocessing
4
5
6class iozone(test.test):
7    """
8    This autotest module runs the IOzone filesystem benchmark. The benchmark
9    generates and measures a variety of file operations. Iozone has been ported
10    to many machines and runs under many operating systems.
11
12    Iozone is useful for performing a broad filesystem analysis of a vendor's
13    computer platform. The benchmark tests file I/O performance for the
14    following operations:
15
16    Read, write, re-read, re-write, read backwards, read strided, fread, fwrite,
17    random read, pread ,mmap, aio_read, aio_write
18
19    @author: Ying Tao (yingtao@cn.ibm.com)
20    @see: http://www.iozone.org
21    """
22    version = 3
23
24    def initialize(self):
25        self.job.require_gcc()
26
27
28    def setup(self, tarball='iozone3_347.tar'):
29        """
30        Builds the given version of IOzone from a tarball.
31        @param tarball: Tarball with IOzone
32        @see: http://www.iozone.org/src/current/iozone3_347.tar
33        """
34        tarball = utils.unmap_url(self.bindir, tarball, self.tmpdir)
35        utils.extract_tarball_to_dir(tarball, self.srcdir)
36        os.chdir(os.path.join(self.srcdir, 'src/current'))
37        utils.system('patch -p3 < ../../../makefile.patch')
38        utils.system('patch -p3 < ../../../clang_fortify.patch')
39
40        ctarget = os.getenv('CTARGET_default')
41
42        if (ctarget == 'armv7a-cros-linux-gnueabihf'):
43            utils.make('linux-arm')
44        elif (ctarget == 'i686-pc-linux-gnu'):
45            utils.make('linux')
46        elif (ctarget == 'x86_64-cros-linux-gnu'):
47            utils.make('linux-AMD64')
48        else:
49            utils.make('linux')
50
51    def run_once(self, dir=None, args=None):
52        """
53        Runs IOzone with appropriate parameters, record raw results in a per
54        iteration raw output file as well as in the results attribute
55
56        @param dir: IOzone file generation dir.
57        @param args: Arguments to the iozone program.
58        """
59        if not dir:
60            dir = self.tmpdir
61        os.chdir(dir)
62        if not args:
63            args = '-a'
64
65        cmd = os.path.join(self.srcdir, 'src', 'current', 'iozone')
66        self.results = utils.system_output('%s %s' % (cmd, args))
67        self.auto_mode = ("-a" in args)
68
69        self.results_path = os.path.join(self.resultsdir,
70                                         'raw_output_%s' % self.iteration)
71        self.analysisdir = os.path.join(self.resultsdir,
72                                        'analysis_%s' % self.iteration)
73
74        utils.open_write_close(self.results_path, self.results)
75
76
77    def __get_section_name(self, desc):
78        return desc.strip().replace(' ', '_')
79
80
81    def generate_keyval(self):
82        """
83        Generates a keylist.
84        """
85        keylist = {}
86
87        if self.auto_mode:
88            labels = ('write', 'rewrite', 'read', 'reread', 'randread',
89                      'randwrite', 'bkwdread', 'recordrewrite',
90                      'strideread', 'fwrite', 'frewrite', 'fread', 'freread')
91            for line in self.results.splitlines():
92                fields = line.split()
93                if len(fields) != 15:
94                    continue
95                try:
96                    fields = tuple([int(i) for i in fields])
97                except ValueError:
98                    continue
99                for l, v in zip(labels, fields[2:]):
100                    key_name = "%d-%d-%s" % (fields[0], fields[1], l)
101                    keylist[key_name] = v
102        else:
103            child_regexp  = re.compile('Children see throughput for[\s]+'
104                            '([\d]+)\s+([-\w]+[-\w\s]*)\=[\s]+([\d\.]*) KB/sec')
105            parent_regexp = re.compile('Parent sees throughput for[\s]+'
106                            '([\d]+)\s+([-\w]+[-\w\s]*)\=[\s]+([\d\.]*) KB/sec')
107
108            KBsec_regexp  = re.compile('\=[\s]+([\d\.]*) KB/sec')
109            KBval_regexp  = re.compile('\=[\s]+([\d\.]*) KB')
110
111            section = None
112            w_count = 0
113
114            for line in self.results.splitlines():
115                line = line.strip()
116
117                # Check for the beginning of a new result section
118                match = child_regexp.search(line)
119                if match:
120                    # Extract the section name and the worker count
121                    w_count = int(match.group(1))
122                    section = self.__get_section_name(match.group(2))
123
124                    # Output the appropriate keyval pair
125                    key_name = '%s-%d-kids' % (section, w_count)
126                    keylist[key_name] = match.group(3)
127                    continue
128
129                # Check for any other interesting lines
130                if '=' in line:
131                    # Is it something we recognize? First check for parent.
132                    match = parent_regexp.search(line)
133                    if match:
134                        # The section name and the worker count better match
135                        p_count = int(match.group(1))
136                        p_secnt = self.__get_section_name(match.group(2))
137                        if p_secnt != section or p_count != w_count:
138                            continue
139
140                        # Set the base name for the keyval
141                        basekey = 'parent'
142                    else:
143                        # Check for the various 'throughput' values
144                        if line[3:26] == ' throughput per thread ':
145                            basekey = line[0:3]
146                            match_x = KBsec_regexp
147                        else:
148                            # The only other thing we expect is 'Min xfer'
149                            if not line.startswith('Min xfer '):
150                                continue
151                            basekey = 'MinXfer'
152                            match_x = KBval_regexp
153
154                        match = match_x.search(line)
155                        if match:
156                            result = match.group(1)
157                            key_name = "%s-%d-%s" % (section, w_count, basekey)
158                            keylist[key_name] = result
159
160        self.write_perf_keyval(keylist)
161
162
163    def postprocess_iteration(self):
164        self.generate_keyval()
165        if self.auto_mode:
166            a = postprocessing.IOzoneAnalyzer(list_files=[self.results_path],
167                                              output_dir=self.analysisdir)
168            a.analyze()
169            p = postprocessing.IOzonePlotter(results_file=self.results_path,
170                                             output_dir=self.analysisdir)
171            p.plot_all()
172