ATLAS Offline Software
Loading...
Searching...
No Matches
trig-test-json.py
Go to the documentation of this file.
1#!/usr/bin/env python
2#
3# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
4#
5
6# This script parses outputs of trigger nightly test post-processing steps
7# and creates a JSON file with extra data other than result codes
8# (which are handled by ART).
9
10import json
11import re
12import sys
13import logging
14import os
15from collections import OrderedDict
16from TrigValTools.TrigARTUtils import first_existing_file, newest_file
17
18logging.basicConfig(stream=sys.stdout,
19 format='%(levelname)-8s %(message)s',
20 level=logging.INFO)
21do_prmon = True
22mod_name = ''
23try:
24 mod_name = 'numpy'
25 import numpy as np
26 mod_name = 'pandas'
27 from pandas import read_csv
28 mod_name = 'scipy.optimize'
29 from scipy.optimize import curve_fit
30 mod_name = 'matplotlib'
31 import matplotlib
32 matplotlib.use('PDF')
33 import matplotlib.pyplot as plt
34except Exception as e:
35 do_prmon = False
36 logging.warning('Failed to import module %s, prmon output analysis will be skipped! %s', mod_name, e)
37
38class LastUpdatedOrderedDict(OrderedDict):
39 'Store items in the order the keys were last added'
40
41 def __setitem__(self, key, value):
42 if key in self:
43 del self[key]
44 OrderedDict.__setitem__(self, key, value)
45
47 if not os.path.isfile(filename):
48 logging.warning(f"Cannot open file {filename}")
49 return None
50 with open(filename) as logfile:
51 if re.search("No error/warning messages found in.*$", logfile.read(), re.MULTILINE) is not None:
52 logging.debug("Number of errors/warnings: 0")
53 return 0
54 logfile.seek(0)
55 match = re.search(r'Found (\d+) (\w+) message\‍(s\‍) in.*$', logfile.read(), re.MULTILINE)
56 if match is None:
57 logging.warning(f"Cannot extract number of messages from {filename}")
58 return None
59 logging.debug(f"Number of {match[2]}s: {match[1]}")
60 return int(match[1])
61
62def get_num_histos(filename):
63 if not os.path.isfile(filename):
64 logging.warning(f"Cannot open file {filename}")
65 return None
66 with open(filename) as logfile:
67 match = re.search(r"Total histograms:.* (\d+)$", logfile.read(), re.MULTILINE)
68 if match is None:
69 logging.warning("Cannot extract number of histograms from {}".format(filename))
70 return None
71 logging.debug(f"Found {match[1]} histograms")
72 return int(match[1])
73
74def convert_to_megabytes(number, unit):
75 multipliers = {
76 'B': 1.0/(1024**2),
77 'kB': 1.0/1024,
78 'MB': 1,
79 "GB": 1024,
80 'TB': 1024**2
81 }
82 for unit_name, mult in multipliers.items():
83 if unit_name == unit:
84 return float(number)*mult
85 logging.error("Unit conversion failed from {} to MB".format(unit))
86 return None
87
88
90 words = line[0].split()
91 mem_end = words[5:7]
92 logging.debug("mem_end = {}".format(mem_end))
93 mem_delta = words[8:10]
94 logging.debug("mem_delta = {}".format(mem_delta))
95 mem_mb = convert_to_megabytes(mem_end[0], mem_end[1])
96 logging.debug("mem_mb = {}".format(mem_mb))
97 delta_mb = convert_to_megabytes(mem_delta[0], mem_delta[1])
98 logging.debug("delta_mb = {}".format(delta_mb))
99 return mem_mb, delta_mb
100
101
102def analyse_perfmon(filename):
103 if not os.path.isfile(filename):
104 logging.warning("Cannot open file {}".format(filename))
105 return None
106 with open(filename) as logfile:
107 first_line = -1
108 last_line = -1
109 all_lines = logfile.readlines()
110 for i, line in enumerate(all_lines):
111 if first_line >= 0 and last_line >= 0:
112 break
113 if "=== [evt - slice] ===" in line:
114 first_line = i
115 elif "=== [fin - slice] ===" in line:
116 last_line = i
117 if first_line < 0 or last_line < 0:
118 logging.warning("Cannot extract memory usage information from {}".format(filename))
119 return None
120 evt_mon_lines = all_lines[first_line:last_line]
121 vmem_line = re.findall("^VMem.*$", '\n'.join(evt_mon_lines), re.MULTILINE)
122 rss_line = re.findall("^RSS.*$", '\n'.join(evt_mon_lines), re.MULTILINE)
123 logging.debug("vmem_line = {}".format(vmem_line))
124 logging.debug("rss_line = {}".format(rss_line))
125 if len(vmem_line) == 0:
126 logging.warning("Cannot extract VMem information from {}".format(filename))
127 if len(rss_line) == 0:
128 logging.warning("Cannot extract RSS information from {}".format(filename))
129 vmem, dvmem = extract_mem_perfmon(vmem_line)
130 rss, drss = extract_mem_perfmon(rss_line)
132 data['vmem'] = "{0:.3f}".format(vmem)
133 data['delta-vmem'] = "{0:.3f}".format(dvmem)
134 data['rss'] = "{0:.3f}".format(rss)
135 data['delta-rss'] = "{0:.3f}".format(drss)
136 return data
137
138
139def mem_func(x_arr, x_trans, init_slope, exec_slope):
140 retval = []
141 for x in x_arr:
142 if x < x_trans:
143 retval.append(init_slope * x)
144 else:
145 retval.append(exec_slope * x + (init_slope - exec_slope) * x_trans)
146 return retval
147
148
149def find_dmem_prmon(xdata, ydata, label, filename):
150 popt, pcov = curve_fit(mem_func, xdata, ydata, bounds=(0, [0.9*max(xdata), np.inf, np.inf]))
151 logging.debug("Fit result: %s", str(popt))
152 plot_prmon(xdata, ydata, label, filename, popt)
153 x_trans = popt[0]
154 x_last = xdata.iloc[-1]
155 dmem_v = mem_func([x_last, x_trans], popt[0], popt[1], popt[2])
156 return dmem_v[0] - dmem_v[1]
157
158
159def plot_prmon(xdata, ydata, name, filename, params=[]):
160 plt.plot(xdata, ydata, 'b-', label=name)
161 if len(params)>0:
162 plt.plot(xdata, mem_func(xdata, *params), 'r-', label='{:s} fit, exec slope={:.2f} kB/s'.format(name, params[2]))
163 plt.xlabel('wtime [s]')
164 plt.ylabel(name+' [kB]')
165 plt.legend()
166 plt.title('{:s} from {:s}'.format(name, filename))
167 plt.savefig('prmon_{:s}.pdf'.format(name), bbox_inches='tight')
168 plt.clf()
169
170
171def analyse_prmon(filename):
172 try:
173 prmon_data = read_csv(filename, sep='\t')
174 except IOError:
175 logging.warning("Cannot open file {}".format(filename))
176 return None
177 time_v = prmon_data['wtime']
178 pss_v = prmon_data['pss']
179 rss_v = prmon_data['rss']
180 vmem_v = prmon_data['vmem']
182 data['vmem'] = "{0:.3f}".format(convert_to_megabytes(max(vmem_v), 'kB'))
183 data['rss'] = "{0:.3f}".format(convert_to_megabytes(max(rss_v), 'kB'))
184 data['pss'] = "{0:.3f}".format(convert_to_megabytes(max(pss_v), 'kB'))
185 if len(time_v) < 80:
186 logging.info('Not enough prmon data points, skipping memory slope fitting')
187 # Save plots without fitting and return
188 plot_prmon(time_v, pss_v, 'pss', filename)
189 plot_prmon(time_v, rss_v, 'rss', filename)
190 plot_prmon(time_v, vmem_v, 'vmem', filename)
191 return data
192 d_pss = find_dmem_prmon(time_v, pss_v, 'pss', filename)
193 d_rss = find_dmem_prmon(time_v, rss_v, 'rss', filename)
194 d_vmem = find_dmem_prmon(time_v, vmem_v, 'vmem', filename)
195 data['delta-vmem'] = "{0:.3f}".format(convert_to_megabytes(d_vmem, 'kB'))
196 data['delta-rss'] = "{0:.3f}".format(convert_to_megabytes(d_rss, 'kB'))
197 data['delta-pss'] = "{0:.3f}".format(convert_to_megabytes(d_pss, 'kB'))
198 return data
199
200
201def main():
203
204 # Get number of errors
205 checklog_log = first_existing_file(['checklog.log', 'CheckLog.log'])
206 ne = get_num_from_checklog(checklog_log) if checklog_log else None
207 logging.debug("ne: {}".format(ne))
208 if ne is None:
209 logging.warning("Failed to read number of errors from the log")
210 data['num-errors'] = 'n/a'
211 else:
212 data['num-errors'] = ne
213
214 # Get number of warnings
215 warnings_log = first_existing_file(['warnings.log', 'Warnings.log'])
216 nw = get_num_from_checklog(warnings_log) if warnings_log else None
217 logging.debug("nw: {}".format(nw))
218 if nw is None:
219 logging.warning("Failed to read number of warnings from the log")
220 data['num-warnings'] = 'n/a'
221 else:
222 data['num-warnings'] = nw
223
224 # Get number of histograms
225 histcount_log = first_existing_file(['histSizes.log', 'HistCount.log'])
226 nh = get_num_histos(histcount_log) if histcount_log else None
227 logging.debug("nh: {}".format(nh))
228 if nh is None:
229 logging.warning("Failed to read number of histograms from the log")
230 data['num-histograms'] = 'n/a'
231 else:
232 data['num-histograms'] = nh
233
234 # Get memory usage information from prmon
235 if do_prmon:
236 prmon_log = newest_file(r'prmon\..*\.txt')
237 if not prmon_log:
238 prmon_log = first_existing_file(['prmon.full.RDOtoRDOTrigger', 'prmon.full.RAWtoESD', 'prmon.full.ESDtoAOD', 'prmon.full.RAWtoALL'])
239 if not prmon_log:
240 logging.info("No prmon output found, the result will be empty")
241 data['prmon'] = 'n/a'
242 else:
243 logging.info("Analysing prmon output from %s", prmon_log)
244 prmon_data = analyse_prmon(prmon_log)
245 if prmon_data is None:
246 logging.warning("Could not analyse prmon output, the result will be empty")
247 data['prmon'] = 'n/a'
248 else:
249 data['prmon'] = prmon_data
250
251 # Get memory usage information from PerfMon
252 perfmon_log = newest_file(r'.*perfmon\.summary\.txt')
253 if not perfmon_log:
254 logging.info("No PerfMon output found, the result will be empty")
255 data['memory-usage'] = 'n/a'
256 else:
257 logging.info("Analysing PerfMon output from %s", perfmon_log)
258 perfmon_data = analyse_perfmon(perfmon_log)
259 if perfmon_data is None:
260 logging.warning("Could not analyse PerfMon output, the result will be empty")
261 data['memory-usage'] = 'n/a'
262 else:
263 data['memory-usage'] = perfmon_data
264
265 # Save data to JSON file
266 with open('extra-results.json', 'w') as outfile:
267 json.dump(data, outfile, indent=4)
268
269
270if "__main__" in __name__:
271 sys.exit(main())
#define max(a, b)
Definition cfImp.cxx:41
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177
get_num_histos(filename)
analyse_perfmon(filename)
plot_prmon(xdata, ydata, name, filename, params=[])
get_num_from_checklog(filename)
convert_to_megabytes(number, unit)
extract_mem_perfmon(line)
find_dmem_prmon(xdata, ydata, label, filename)
analyse_prmon(filename)
mem_func(x_arr, x_trans, init_slope, exec_slope)