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
39        ctarget = os.getenv('CTARGET_default')
40
41        if (ctarget == 'armv7a-cros-linux-gnueabi'):
42            utils.make('linux-arm')
43        elif (ctarget == 'i686-pc-linux-gnu'):
44            utils.make('linux')
45        elif (ctarget == 'x86_64-cros-linux-gnu'):
46            utils.make('linux-AMD64')
47        else:
48            utils.make('linux')
49
50    def run_once(self, dir=None, args=None):
51        """
52        Runs IOzone with appropriate parameters, record raw results in a per
53        iteration raw output file as well as in the results attribute
54
55        @param dir: IOzone file generation dir.
56        @param args: Arguments to the iozone program.
57        """
58        if not dir:
59            dir = self.tmpdir
60        os.chdir(dir)
61        if not args:
62            args = '-a'
63
64        cmd = os.path.join(self.srcdir, 'src', 'current', 'iozone')
65        self.results = utils.system_output('%s %s' % (cmd, args))
66        self.auto_mode = ("-a" in args)
67
68        self.results_path = os.path.join(self.resultsdir,
69                                         'raw_output_%s' % self.iteration)
70        self.analysisdir = os.path.join(self.resultsdir,
71                                        'analysis_%s' % self.iteration)
72
73        utils.open_write_close(self.results_path, self.results)
74
75
76    def __get_section_name(self, desc):
77        return desc.strip().replace(' ', '_')
78
79
80    def generate_keyval(self):
81        keylist = {}
82
83        if self.auto_mode:
84            labels = ('write', 'rewrite', 'read', 'reread', 'randread',
85                      'randwrite', 'bkwdread', 'recordrewrite',
86                      'strideread', 'fwrite', 'frewrite', 'fread', 'freread')
87            for line in self.results.splitlines():
88                fields = line.split()
89                if len(fields) != 15:
90                    continue
91                try:
92                    fields = tuple([int(i) for i in fields])
93                except ValueError:
94                    continue
95                for l, v in zip(labels, fields[2:]):
96                    key_name = "%d-%d-%s" % (fields[0], fields[1], l)
97                    keylist[key_name] = v
98        else:
99            child_regexp  = re.compile('Children see throughput for[\s]+'
100                            '([\d]+)\s+([-\w]+[-\w\s]*)\=[\s]+([\d\.]*) KB/sec')
101            parent_regexp = re.compile('Parent sees throughput for[\s]+'
102                            '([\d]+)\s+([-\w]+[-\w\s]*)\=[\s]+([\d\.]*) KB/sec')
103
104            KBsec_regexp  = re.compile('\=[\s]+([\d\.]*) KB/sec')
105            KBval_regexp  = re.compile('\=[\s]+([\d\.]*) KB')
106
107            section = None
108            w_count = 0
109
110            for line in self.results.splitlines():
111                line = line.strip()
112
113                # Check for the beginning of a new result section
114                match = child_regexp.search(line)
115                if match:
116                    # Extract the section name and the worker count
117                    w_count = int(match.group(1))
118                    section = self.__get_section_name(match.group(2))
119
120                    # Output the appropriate keyval pair
121                    key_name = '%s-%d-kids' % (section, w_count)
122                    keylist[key_name] = match.group(3)
123                    continue
124
125                # Check for any other interesting lines
126                if '=' in line:
127                    # Is it something we recognize? First check for parent.
128                    match = parent_regexp.search(line)
129                    if match:
130                        # The section name and the worker count better match
131                        p_count = int(match.group(1))
132                        p_secnt = self.__get_section_name(match.group(2))
133                        if p_secnt != section or p_count != w_count:
134                            continue
135
136                        # Set the base name for the keyval
137                        basekey = 'parent'
138                    else:
139                        # Check for the various 'throughput' values
140                        if line[3:26] == ' throughput per thread ':
141                            basekey = line[0:3]
142                            match_x = KBsec_regexp
143                        else:
144                            # The only other thing we expect is 'Min xfer'
145                            if not line.startswith('Min xfer '):
146                                continue
147                            basekey = 'MinXfer'
148                            match_x = KBval_regexp
149
150                        match = match_x.search(line)
151                        if match:
152                            result = match.group(1)
153                            key_name = "%s-%d-%s" % (section, w_count, basekey)
154                            keylist[key_name] = result
155
156        self.write_perf_keyval(keylist)
157
158
159    def postprocess_iteration(self):
160        self.generate_keyval()
161        if self.auto_mode:
162            a = postprocessing.IOzoneAnalyzer(list_files=[self.results_path],
163                                              output_dir=self.analysisdir)
164            a.analyze()
165            p = postprocessing.IOzonePlotter(results_file=self.results_path,
166                                             output_dir=self.analysisdir)
167            p.plot_all()
168