Enable vnf/tg instantiate as blocking call.
[yardstick.git] / yardstick / benchmark / scenarios / storage / fio.py
1 ##############################################################################
2 # Copyright (c) 2015 Huawei Technologies Co.,Ltd.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9 from __future__ import absolute_import
10 from __future__ import print_function
11
12 import logging
13
14 import pkg_resources
15 from oslo_serialization import jsonutils
16
17 import yardstick.ssh as ssh
18 from yardstick.benchmark.scenarios import base
19
20 LOG = logging.getLogger(__name__)
21
22
23 class Fio(base.Scenario):
24     """Execute fio benchmark in a host
25
26   Parameters
27     filename - file name for fio workload
28         type:    string
29         unit:    na
30         default: /home/ubuntu/data.raw
31     bs - block size used for the io units
32         type:    int
33         unit:    bytes
34         default: 4k
35     iodepth - number of iobuffers to keep in flight
36         type:    int
37         unit:    na
38         default: 1
39     rw - type of io pattern [read, write, randwrite, randread, rw, randrw]
40         type:    string
41         unit:    na
42         default: write
43     rwmixwrite - percentage of a mixed workload that should be writes
44         type: int
45         unit: percentage
46         default: 50
47     ramp_time - run time before logging any performance
48         type:    int
49         unit:    seconds
50         default: 20
51     direct - whether use non-buffered I/O or not
52         type:    boolean
53         unit:    na
54         default: 1
55     size - total size of I/O for this job.
56         type:    string
57         unit:    na
58         default: 1g
59     numjobs - number of clones (processes/threads performing the same workload) of this job
60         type:    int
61         unit:    na
62         default: 1
63
64     Read link below for more fio args description:
65         http://www.bluestop.org/fio/HOWTO.txt
66     """
67     __scenario_type__ = "Fio"
68
69     TARGET_SCRIPT = "fio_benchmark.bash"
70
71     def __init__(self, scenario_cfg, context_cfg):
72         self.scenario_cfg = scenario_cfg
73         self.context_cfg = context_cfg
74         self.setup_done = False
75
76     def setup(self):
77         """scenario setup"""
78         self.target_script = pkg_resources.resource_filename(
79             "yardstick.benchmark.scenarios.storage",
80             Fio.TARGET_SCRIPT)
81         host = self.context_cfg["host"]
82
83         self.client = ssh.SSH.from_node(host, defaults={"user": "root"})
84         self.client.wait(timeout=600)
85
86         # copy script to host
87         self.client._put_file_shell(self.target_script, '~/fio.sh')
88
89         self.setup_done = True
90
91     def run(self, result):
92         """execute the benchmark"""
93         default_args = "-ioengine=libaio -group_reporting -time_based -time_based " \
94             "--output-format=json"
95
96         if not self.setup_done:
97             self.setup()
98
99         options = self.scenario_cfg["options"]
100         filename = options.get("filename", "/home/ubuntu/data.raw")
101         bs = options.get("bs", "4k")
102         iodepth = options.get("iodepth", "1")
103         rw = options.get("rw", "write")
104         ramp_time = options.get("ramp_time", 20)
105         size = options.get("size", "1g")
106         direct = options.get("direct", "1")
107         numjobs = options.get("numjobs", "1")
108         rwmixwrite = options.get("rwmixwrite", 50)
109         name = "yardstick-fio"
110         # if run by a duration runner
111         duration_time = self.scenario_cfg["runner"].get("duration", None) \
112             if "runner" in self.scenario_cfg else None
113         # if run by an arithmetic runner
114         arithmetic_time = options.get("duration", None)
115         if duration_time:
116             runtime = duration_time
117         elif arithmetic_time:
118             runtime = arithmetic_time
119         else:
120             runtime = 30
121
122         cmd_args = "-filename=%s -direct=%s -bs=%s -iodepth=%s -rw=%s -rwmixwrite=%s " \
123                    "-size=%s -ramp_time=%s -numjobs=%s -runtime=%s -name=%s %s" \
124                    % (filename, direct, bs, iodepth, rw, rwmixwrite, size, ramp_time, numjobs,
125                       runtime, name, default_args)
126         cmd = "sudo bash fio.sh %s %s" % (filename, cmd_args)
127         LOG.debug("Executing command: %s", cmd)
128         # Set timeout, so that the cmd execution does not exit incorrectly
129         # when the test run time is last long
130         timeout = int(ramp_time) + int(runtime) + 600
131         status, stdout, stderr = self.client.execute(cmd, timeout=timeout)
132         if status:
133             raise RuntimeError(stderr)
134
135         raw_data = jsonutils.loads(stdout)
136
137         # The bandwidth unit is KB/s, and latency unit is us
138         if rw in ["read", "randread", "rw", "randrw"]:
139             result["read_bw"] = raw_data["jobs"][0]["read"]["bw"]
140             result["read_iops"] = raw_data["jobs"][0]["read"]["iops"]
141             result["read_lat"] = raw_data["jobs"][0]["read"]["lat"]["mean"]
142         if rw in ["write", "randwrite", "rw", "randrw"]:
143             result["write_bw"] = raw_data["jobs"][0]["write"]["bw"]
144             result["write_iops"] = raw_data["jobs"][0]["write"]["iops"]
145             result["write_lat"] = raw_data["jobs"][0]["write"]["lat"]["mean"]
146
147         if "sla" in self.scenario_cfg:
148             sla_error = ""
149             for k, v in result.items():
150                 if k not in self.scenario_cfg['sla']:
151                     continue
152
153                 if "lat" in k:
154                     # For lattency small value is better
155                     max_v = float(self.scenario_cfg['sla'][k])
156                     if v > max_v:
157                         sla_error += "%s %f > sla:%s(%f); " % (k, v, k, max_v)
158                 else:
159                     # For bandwidth and iops big value is better
160                     min_v = int(self.scenario_cfg['sla'][k])
161                     if v < min_v:
162                         sla_error += "%s %d < " \
163                             "sla:%s(%d); " % (k, v, k, min_v)
164
165             assert sla_error == "", sla_error
166
167
168 def _test():
169     """internal test function"""
170     key_filename = pkg_resources.resource_filename("yardstick.resources",
171                                                    "files/yardstick_key")
172     ctx = {
173         "host": {
174             "ip": "10.229.47.137",
175             "user": "root",
176             "key_filename": key_filename
177         }
178     }
179
180     logger = logging.getLogger("yardstick")
181     logger.setLevel(logging.DEBUG)
182
183     options = {
184         "filename": "/home/ubuntu/data.raw",
185         "bs": "4k",
186         "iodepth": "1",
187         "rw": "rw",
188         "ramp_time": 1,
189         "duration": 10
190     }
191     result = {}
192     args = {"options": options}
193
194     fio = Fio(args, ctx)
195     fio.run(result)
196     print(result)
197
198
199 if __name__ == '__main__':
200     _test()