Merge "heat: close file before parsing template"
[yardstick.git] / yardstick / benchmark / scenarios / compute / cyclictest.py
1 ##############################################################################
2 # Copyright (c) 2015 Huawei Technologies Co.,Ltd and other.
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 import os
14 import re
15 import time
16
17 import pkg_resources
18 from oslo_serialization import jsonutils
19
20 import yardstick.ssh as ssh
21 from yardstick.benchmark.scenarios import base
22
23 LOG = logging.getLogger(__name__)
24 LOG.setLevel(logging.DEBUG)
25
26
27 class Cyclictest(base.Scenario):
28     """Execute cyclictest benchmark on guest vm
29
30   Parameters
31     affinity - run thread #N on processor #N, if possible
32         type:    int
33         unit:    na
34         default: 1
35     interval - base interval of thread
36         type:    int
37         unit:    us
38         default: 1000
39     loops - number of loops, 0 for endless
40         type:    int
41         unit:    na
42         default: 1000
43     priority - priority of highest prio thread
44         type:    int
45         unit:    na
46         default: 99
47     threads - number of threads
48         type:    int
49         unit:    na
50         default: 1
51     histogram - dump a latency histogram to stdout after the run
52                 here set the max time to be tracked
53         type:    int
54         unit:    ms
55         default: 90
56
57     Read link below for more fio args description:
58         https://rt.wiki.kernel.org/index.php/Cyclictest
59     """
60     __scenario_type__ = "Cyclictest"
61
62     TARGET_SCRIPT = "cyclictest_benchmark.bash"
63     WORKSPACE = "/root/workspace/"
64     REBOOT_CMD_PATTERN = r";\s*reboot\b"
65
66     def __init__(self, scenario_cfg, context_cfg):
67         self.scenario_cfg = scenario_cfg
68         self.context_cfg = context_cfg
69         self.setup_done = False
70
71     def _put_files(self, client):
72         setup_options = self.scenario_cfg["setup_options"]
73         rpm_dir = setup_options["rpm_dir"]
74         script_dir = setup_options["script_dir"]
75         image_dir = setup_options["image_dir"]
76         LOG.debug("Send RPMs from %s to workspace %s",
77                   rpm_dir, self.WORKSPACE)
78         client.put(rpm_dir, self.WORKSPACE, recursive=True)
79         LOG.debug("Send scripts from %s to workspace %s",
80                   script_dir, self.WORKSPACE)
81         client.put(script_dir, self.WORKSPACE, recursive=True)
82         LOG.debug("Send guest image from %s to workspace %s",
83                   image_dir, self.WORKSPACE)
84         client.put(image_dir, self.WORKSPACE, recursive=True)
85
86     def _connect_host(self):
87         host = self.context_cfg["host"]
88         user = host.get("user", "root")
89         ip = host.get("ip", None)
90         key_filename = host.get("key_filename", "~/.ssh/id_rsa")
91
92         LOG.debug("user:%s, host:%s", user, ip)
93         self.host = ssh.SSH(user, ip, key_filename=key_filename)
94         self.host.wait(timeout=600)
95
96     def _connect_guest(self):
97         host = self.context_cfg["host"]
98         user = host.get("user", "root")
99         ip = host.get("ip", None)
100         ssh_port = host.get("ssh_port", 5555)
101         key_filename = host.get("key_filename", "~/.ssh/id_rsa")
102
103         LOG.debug("user:%s, host:%s", user, ip)
104         self.guest = ssh.SSH(user, ip, port=ssh_port,
105                              key_filename=key_filename)
106         self.guest.wait(timeout=600)
107
108     def _run_setup_cmd(self, client, cmd):
109         LOG.debug("Run cmd: %s", cmd)
110         status, stdout, stderr = client.execute(cmd)
111         if status:
112             if re.search(self.REBOOT_CMD_PATTERN, cmd):
113                 LOG.debug("Error on reboot")
114             else:
115                 raise RuntimeError(stderr)
116
117     def _run_host_setup_scripts(self, scripts):
118         setup_options = self.scenario_cfg["setup_options"]
119         script_dir = os.path.basename(setup_options["script_dir"])
120
121         for script in scripts:
122             cmd = "cd %s/%s; export PATH=./:$PATH; %s" %\
123                   (self.WORKSPACE, script_dir, script)
124             self._run_setup_cmd(self.host, cmd)
125
126             if re.search(self.REBOOT_CMD_PATTERN, cmd):
127                 time.sleep(3)
128                 self._connect_host()
129
130     def _run_guest_setup_scripts(self, scripts):
131         setup_options = self.scenario_cfg["setup_options"]
132         script_dir = os.path.basename(setup_options["script_dir"])
133
134         for script in scripts:
135             cmd = "cd %s/%s; export PATH=./:$PATH; %s" %\
136                   (self.WORKSPACE, script_dir, script)
137             self._run_setup_cmd(self.guest, cmd)
138
139             if re.search(self.REBOOT_CMD_PATTERN, cmd):
140                 time.sleep(3)
141                 self._connect_guest()
142
143     def setup(self):
144         """scenario setup"""
145         setup_options = self.scenario_cfg["setup_options"]
146         host_setup_seqs = setup_options["host_setup_seqs"]
147         guest_setup_seqs = setup_options["guest_setup_seqs"]
148
149         self._connect_host()
150         self._put_files(self.host)
151         self._run_host_setup_scripts(host_setup_seqs)
152
153         self._connect_guest()
154         self._put_files(self.guest)
155         self._run_guest_setup_scripts(guest_setup_seqs)
156
157         # copy script to host
158         self.target_script = pkg_resources.resource_filename(
159             "yardstick.benchmark.scenarios.compute",
160             Cyclictest.TARGET_SCRIPT)
161         self.guest._put_file_shell(
162             self.target_script, '~/cyclictest_benchmark.sh')
163
164         self.setup_done = True
165
166     def run(self, result):
167         """execute the benchmark"""
168         default_args = "-m -n -q"
169
170         if not self.setup_done:
171             self.setup()
172
173         options = self.scenario_cfg["options"]
174         affinity = options.get("affinity", 1)
175         interval = options.get("interval", 1000)
176         priority = options.get("priority", 99)
177         loops = options.get("loops", 1000)
178         threads = options.get("threads", 1)
179         histogram = options.get("histogram", 90)
180
181         cmd_args = "-a %s -i %s -p %s -l %s -t %s -h %s %s" \
182                    % (affinity, interval, priority, loops,
183                       threads, histogram, default_args)
184         cmd = "bash cyclictest_benchmark.sh %s" % (cmd_args)
185         LOG.debug("Executing command: %s", cmd)
186         status, stdout, stderr = self.guest.execute(cmd)
187         if status:
188             raise RuntimeError(stderr)
189
190         result.update(jsonutils.loads(stdout))
191
192         if "sla" in self.scenario_cfg:
193             sla_error = ""
194             for t, latency in result.items():
195                 if 'max_%s_latency' % t not in self.scenario_cfg['sla']:
196                     continue
197
198                 sla_latency = int(self.scenario_cfg['sla'][
199                                   'max_%s_latency' % t])
200                 latency = int(latency)
201                 if latency > sla_latency:
202                     sla_error += "%s latency %d > sla:max_%s_latency(%d); " % \
203                         (t, latency, t, sla_latency)
204             assert sla_error == "", sla_error
205
206
207 def _test():    # pragma: no cover
208     """internal test function"""
209     key_filename = pkg_resources.resource_filename("yardstick.resources",
210                                                    "files/yardstick_key")
211     ctx = {
212         "host": {
213             "ip": "10.229.47.137",
214             "user": "root",
215             "key_filename": key_filename
216         }
217     }
218
219     logger = logging.getLogger("yardstick")
220     logger.setLevel(logging.DEBUG)
221
222     options = {
223         "affinity": 2,
224         "interval": 100,
225         "priority": 88,
226         "loops": 10000,
227         "threads": 2,
228         "histogram": 80
229     }
230     sla = {
231         "max_min_latency": 100,
232         "max_avg_latency": 500,
233         "max_max_latency": 1000,
234     }
235     args = {
236         "options": options,
237         "sla": sla
238     }
239     result = {}
240
241     cyclictest = Cyclictest(args, ctx)
242     cyclictest.run(result)
243     print(result)
244
245
246 if __name__ == '__main__':    # pragma: no cover
247     _test()