pkt_gen: Adding MoonGen traffic generator
[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 import time
22 from tools import tasks
23 from tools import systeminfo
24 from tools.load_gen.load_gen import ILoadGenerator
25
26 class Stress(ILoadGenerator):
27     """Wrapper around stress tool, which generates load based on testcase
28     configuration parameter 'load'
29     """
30     _process_args = {
31         'cmd': ['sudo', 'stress'],
32         'timeout': 5,
33         'logfile': '/tmp/stress.log',
34         'expect': r'stress: info:',
35         'name': 'stress'
36     }
37     _logger = logging.getLogger(__name__)
38
39     def __init__(self, stress_config):
40         self._running = False
41         # copy stress process setings before its modification
42         process_args = copy.deepcopy(self._process_args)
43         # check if load is requested and correctly configured
44         if not (stress_config and 'load' in stress_config and
45                 'pattern' in stress_config and stress_config['load'] > 0):
46             self._logger.error('stress test is not enabled')
47             return
48
49         if stress_config['load'] < 0 or stress_config['load'] > 100:
50             self._logger.error('defined load %s is out of range 0-100',
51                                stress_config['load'])
52             return
53
54         # check if load tool binary is available
55         if not ('tool' in stress_config) or subprocess.call("which " + stress_config['tool'], shell=True) > 0:
56             self._logger.error("stress tool binary '%s' is not available", stress_config['tool'])
57             return
58
59         # calculate requested load details and load split among different
60         # types of workers
61         cpus = systeminfo.get_cpu_cores()
62         if 'reserved' in stress_config:
63             cpus = cpus - int(stress_config['reserved'])
64             if cpus < 1:
65                 cpus = 1
66
67         workers = round(cpus/100 * int(stress_config['load']))
68         cmd_dict = {}
69         p_types = {}
70         p_total = 0
71         for p_type in ('c', 'i', 'm'):
72             p_count = stress_config['pattern'].lower().count(p_type)
73             if p_count > 0:
74                 p_types[p_type] = p_count
75                 p_total += p_count
76         if p_total < 1:
77             self._logger.error('stress test pattern does not contain any of ' \
78                                'c, i or m pattern types')
79             return
80         for p_type in p_types:
81             cmd_dict['-'+p_type] = round(workers* p_types[p_type] / p_total)
82
83         # check for memory load in case that memory workers are detected
84         # in case of error or 0%, memory size is not specified and default
85         # amount of memory will be used by stress tool
86         if '-m' in cmd_dict and cmd_dict['-m'] > 0:
87             if 'load_memory' in stress_config and \
88                 stress_config['load_memory'] > 0 and \
89                 stress_config['load_memory'] <= 100:
90
91                 mem = systeminfo.get_memory_bytes()
92                 if mem:
93                     cmd_dict['--vm-bytes'] = round(int(mem) / 100 * \
94                         stress_config['load_memory'] / cmd_dict['-m'])
95
96         # append stress arguments to cmd list used by parent class Process
97         for key, value in cmd_dict.items():
98             process_args['cmd'].append(key)
99             process_args['cmd'].append(str(value))
100
101         # append load generator options if specified
102         if 'options' in stress_config:
103             process_args['cmd'].append(stress_config['options'])
104
105         # initialize load generator and remember it
106         super(Stress, self).__init__(**process_args)
107         self._running = True
108
109     def start(self):
110         """Start stress load if it was requested
111         """
112         if self._running:
113             super(Stress, self).start()
114
115     def kill(self, signal='-15', sleep=2):
116         """
117         Kill stress load if it is active
118         """
119         if self._running and self._child and self._child.isalive():
120             tasks.run_task(['sudo', 'pkill', signal, self._proc_name], self._logger)
121         time.sleep(sleep)
122
123         self._logger.info(
124             'Log available at %s', self._logfile)
125         self._running = False