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