Support of configurable background load and implementation of LTD.CPU.RFC2544.0Packet...
[vswitchperf.git] / tools / load_gen / stress / stress.py
1 # Copyright 2015 Intel Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #   http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 """Module with implementation of wrapper around the stress tool
16 """
17
18 import logging
19 import subprocess
20 import copy
21 from tools import tasks
22 from tools import systeminfo
23 from tools.load_gen.load_gen import ILoadGenerator
24
25 class Stress(ILoadGenerator):
26     """Wrapper around stress tool, which generates load based on testcase
27     configuration parameter 'load'
28     """
29     _process_args = {
30         'cmd': ['sudo', 'stress'],
31         'timeout': 5,
32         'logfile': '/tmp/stress.log',
33         'expect': r'stress: info:',
34         'name': 'stress'
35     }
36     _logger = logging.getLogger(__name__)
37
38     def __init__(self, stress_config):
39         self._running = False
40         # copy stress process setings before its modification
41         process_args = copy.deepcopy(self._process_args)
42         # check if load is requested and correctly configured
43         if not (stress_config and 'load' in stress_config and
44                 'pattern' in stress_config and stress_config['load'] > 0):
45             self._logger.error('stress test is not enabled')
46             return
47
48         if stress_config['load'] < 0 or stress_config['load'] > 100:
49             self._logger.error('defined load %s is out of range 0-100',
50                                stress_config['load'])
51             return
52
53         # check if load tool binary is available
54         if not ('tool' in stress_config) or subprocess.call("which " + stress_config['tool'], shell=True) > 0:
55             self._logger.error("stress tool binary '%s' is not available", stress_config['tool'])
56             return
57
58         # calculate requested load details and load split among different
59         # types of workers
60         cpus = systeminfo.get_cpu_cores()
61         if 'reserved' in stress_config:
62             cpus = cpus - int(stress_config['reserved'])
63             if cpus < 1:
64                 cpus = 1
65
66         workers = round(cpus/100 * int(stress_config['load']))
67         cmd_dict = {}
68         p_types = {}
69         p_total = 0
70         for p_type in ('c', 'i', 'm'):
71             p_count = stress_config['pattern'].lower().count(p_type)
72             if p_count > 0:
73                 p_types[p_type] = p_count
74                 p_total += p_count
75         if p_total < 1:
76             self._logger.error('stress test pattern does not contain any of ' \
77                                'c, i or m pattern types')
78             return
79         for p_type in p_types:
80             cmd_dict['-'+p_type] = round(workers* p_types[p_type] / p_total)
81
82         # check for memory load in case that memory workers are detected
83         # in case of error or 0%, memory size is not specified and default
84         # amount of memory will be used by stress tool
85         if '-m' in cmd_dict and cmd_dict['-m'] > 0:
86             if 'load_memory' in stress_config and \
87                 stress_config['load_memory'] > 0 and \
88                 stress_config['load_memory'] <= 100:
89
90                 mem = systeminfo.get_memory_bytes()
91                 if mem:
92                     cmd_dict['--vm-bytes'] = round(int(mem) / 100 * \
93                         stress_config['load_memory'] / cmd_dict['-m'])
94
95         # append stress arguments to cmd list used by parent class Process
96         for key, value in cmd_dict.items():
97             process_args['cmd'].append(key)
98             process_args['cmd'].append(str(value))
99
100         # append load generator options if specified
101         if 'options' in stress_config:
102             process_args['cmd'].append(stress_config['options'])
103
104         # initialize load generator and remember it
105         super(Stress, self).__init__(**process_args)
106         self._running = True
107
108     def start(self):
109         """Start stress load if it was requested
110         """
111         if self._running:
112             super(Stress, self).start()
113
114     def kill(self):
115         """
116         Kill stress load if it is active
117         """
118         if self._running and self._child and self._child.isalive():
119             tasks.run_task(['sudo', 'pkill', self._proc_name],
120                            self._logger)
121
122         self._logger.info(
123             'Log available at %s', self._logfile)
124         self._running = False