1 # Copyright 2015 Intel Corporation.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
15 """module for statistics collection by pidstat
17 Provides system statistics collected between calls of start() and stop()
18 by command line tool pidstat (part of sysstat package)
20 This requires the following setting in your config:
22 * PIDSTAT_MONITOR = ['ovs-vswitchd', 'ovsdb-server', 'kvm']
23 processes to be monitorred by pidstat
25 * PIDSTAT_OPTIONS = '-dur'
26 options which will be passed to pidstat, i.e. what
27 statistics should be collected by pidstat
29 * LOG_FILE_PIDSTAT = 'pidstat.log'
30 log file for pidstat; it defines suffix, which will be added
31 to testcase name. Pidstat detailed statistics will be stored separately
34 If this doesn't exist, the application will raise an exception
42 from collections import OrderedDict
43 from tools import tasks
44 from tools import systeminfo
45 from conf import settings
46 from tools.collectors.collector import collector
48 _ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
50 class Pidstat(collector.ICollector):
51 """A logger of system statistics based on pidstat
53 It collects statistics based on configuration
55 _logger = logging.getLogger(__name__)
57 def __init__(self, results_dir, test_name):
59 Initialize collection of statistics
61 self._log = os.path.join(results_dir,
62 settings.getValue('LOG_FILE_PIDSTAT') +
63 '_' + test_name + '.log')
64 self._results = OrderedDict()
69 Starts collection of statistics by pidstat and stores them
70 into the file in directory with test results
72 monitor = settings.getValue('PIDSTAT_MONITOR')
73 self._logger.info('Statistics are requested for: ' + ', '.join(monitor))
74 pids = systeminfo.get_pids(monitor)
76 with open(self._log, 'w') as logfile:
77 cmd = ['sudo', 'LC_ALL=' + settings.getValue('DEFAULT_CMD_LOCALE'),
78 'pidstat', settings.getValue('PIDSTAT_OPTIONS'),
80 str(settings.getValue('PIDSTAT_SAMPLE_INTERVAL'))]
81 self._logger.debug('%s', ' '.join(cmd))
82 self._pid = subprocess.Popen(cmd, stdout=logfile, bufsize=0).pid
86 Stops collection of statistics by pidstat and stores statistic summary
87 for each monitored process into self._results dictionary
91 # in python3.4 it's not possible to send signal through pid of sudo
92 # process, so all pidstat processes are interupted instead
94 tasks.run_task(['sudo', 'pkill', '--signal', '2', 'pidstat'],
98 'Pidstat log available at %s', self._log)
100 # let's give pidstat some time to write down average summary
103 # parse average values from log file and store them to _results dict
104 self._results = OrderedDict()
105 logfile = open(self._log, 'r')
107 line = logfile.readline()
110 # process only lines with summary
111 if line[0:7] == 'Average':
112 if line[-7:] == 'Command':
113 # store header fields if detected
114 tmp_header = line[8:].split()
116 # combine stored header fields with actual values
117 tmp_res = OrderedDict(zip(tmp_header,
119 # use process's name and its pid as unique key
120 key = tmp_res.pop('Command') + '_' + tmp_res['PID']
121 # store values for given command into results dict
122 if key in self._results:
123 self._results[key].update(tmp_res)
125 self._results[key] = tmp_res
127 line = logfile.readline()
129 def get_results(self):
130 """Returns collected statistics.
134 def print_results(self):
135 """Logs collected statistics.
137 for process in self._results:
138 logging.info("Process: " + '_'.join(process.split('_')[:-1]))
139 for(key, value) in self._results[process].items():
140 logging.info(" Statistic: " + str(key) +
141 ", Value: " + str(value))