ATLAS Offline Software
perfmonmt-plotter.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 # Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
4 
5 # @author: Hasan Ozturk <haozturk@cern.ch>
6 
7 __author__ = "Hasan Ozturk <haozturk@cern.ch"
8 __doc__ = "A python module which parses the PerfMonMTSvc results and makes plots"
9 
10 import json
11 
12 import matplotlib
13 matplotlib.use('PDF') # use PDF backend
14 import matplotlib.pyplot as plt
15 import numpy as np
16 
17 import operator
18 import argparse
19 import tarfile
20 
21 colors = { "dCPU" : "tab:blue", "dWall" : "tab:orange",
22  "dVmem" : "tab:blue", "dPss" : "tab:green",
23  "dRss" : "tab:orange", "dSwap" : "tab:red",
24  "cpuTime" : "tab:blue", "wallTime" : "tab:orange",
25  "malloc" : "tab:orange", "vmem" : "tab:blue",
26  "pss" : "tab:green", "rss" : "tab:orange", "swap" : "tab:red" }
27 
28 def plotBarChart(params):
29 
30  ax = params["ax"]
31 
32  offset = 1 - len(params["vals"])
33  for metric in params["vals"]:
34  vals = params["vals"][metric]
35  ax.barh(params["index"] + (offset*0.5)*params["width"], vals, params["width"],
36  color = colors[metric], alpha=0.8, label = metric)
37  offset += 2
38 
39  ax.set_xlabel(params["xlabel"], fontsize=params['xlabelFontSize'])
40  ax.set_ylabel(params["ylabel"], fontsize=params['ylabelFontSize'])
41  ax.set_title(params["title"], fontsize=params['titleFontSize'], fontweight='bold')
42  ax.set_yticks(params["index"])
43  ax.set_yticklabels(params["yTickLabels"])
44  handles, labels = ax.get_legend_handles_labels()
45  ax.legend(reversed(handles), reversed(labels), prop={'size': params['legendFontSize']})
46  ax.tick_params(axis='both', which='major', labelsize=30)
47  ax.grid(linestyle=':',linewidth=0.1)
48 
49 def plotLineChart(params):
50 
51  ax = params['ax']
52 
53  for label, metric in params['yVals'].items():
54  ax.plot(params['xVals'], metric, color = colors[label], label = label)
55 
56  ax.set_xlabel(params['xlabel'])
57  ax.set_ylabel(params['ylabel'])
58 
59  ax.set_xticks(params['xVals'])
60  ax.set_xticklabels(params['xVals'], rotation='vertical')
61  ax.tick_params(axis='both', which='major', labelsize=10)
62  ax.set_title(params['title'])
63  ax.legend()
64  ax.grid(linestyle=':',linewidth=0.1)
65 
66 def sortComponents(compNames, measDict, compCountPerPlot):
67 
68  metricToCompMeasDict = {} # This is a lookup map, we use it to map components to measurements after sorting
69  measList = []
70  for metric, meas in measDict.items():
71 
72  metricToCompMeasDict[metric] = dict(zip(compNames, meas))
73  measList.append(meas)
74 
75  # Sort by the sum of each metric: Ex: Sort by (vmem + malloc) for memMon
76  sortByList = [sum(x) for x in zip(*measList)]
77  sortedCompMeasTuple = sorted(dict(zip(compNames, sortByList)).items(), key = operator.itemgetter(1))
78  sortedCompNames = [ compMeas[0] for compMeas in sortedCompMeasTuple]
79 
80  sortedMeasurements = {}
81  # Populate sortedMeasurements according to the sortedCompNames
82  for comp in sortedCompNames[-compCountPerPlot:]:
83  for metric, compMeas in metricToCompMeasDict.items():
84 
85  if metric not in sortedMeasurements:
86  sortedMeasurements[metric] = []
87 
88  sortedMeasurements[metric].append(compMeas[comp])
89 
90 
91 
92  return sortedCompNames[-compCountPerPlot:], sortedMeasurements
93 
94 def plotSnapshotLevel(snapshotData, plotname):
95 
96  # Collect data
97  stepNames, dCPUVals, dWallVals, dVmemVals, dRssVals, dPssVals, dSwapVals = [],[],[],[],[],[],[]
98  for step in ['Finalize', 'FirstEvent', 'Execute', 'Initialize', 'Configure']:
99  meas = snapshotData[step]
100 
101  # Show in seconds
102  dCPU = meas["dCPU"] * 0.001
103  dWall = meas["dWall"] * 0.001
104 
105  # Show in megabytes
106  dVmem = meas["dVmem"] * 0.001
107  dRss = meas["dRss"] * 0.001
108  dPss = meas["dPss"] * 0.001
109  dSwap = meas["dSwap"] * 0.001
110 
111  stepNames.append(step)
112  dCPUVals.append(dCPU)
113  dWallVals.append(dWall)
114 
115  dVmemVals.append(dVmem)
116  dRssVals.append(dRss)
117  dPssVals.append(dPss)
118  dSwapVals.append(dSwap)
119 
120  timeMonVals = {
121  "dCPU": dCPUVals,
122  "dWall": dWallVals
123  }
124 
125  memMonVals = {
126  "dVmem": dVmemVals,
127  "dRss": dRssVals,
128  "dPss": dPssVals,
129  "dSwap": dSwapVals,
130  }
131 
132 
133  timeMonFig, timeMonAx = plt.subplots(figsize=(20,15))
134  memMonFig, memMonAx = plt.subplots(figsize=(20,15))
135 
136  timeMonParams = {
137  "ax": timeMonAx,
138  "index": np.arange(len(stepNames)),
139  "width": 0.5/len(timeMonVals),
140  "vals": timeMonVals,
141  "yTickLabels": stepNames,
142  "xlabel": "Time [sec]",
143  "ylabel": "Steps",
144  "title": "Snapshot Level Monitoring: Time Metrics",
145  "titleFontSize": 40,
146  "xlabelFontSize": 40,
147  "ylabelFontSize": 40,
148  "legendFontSize": 30
149 
150  }
151 
152  memMonParams = {
153  "ax": memMonAx,
154  "index": np.arange(len(stepNames)),
155  "width": 0.5/len(memMonVals), # Think about this
156  "vals": memMonVals,
157  "yTickLabels": stepNames,
158  "xlabel": "Memory [MB]",
159  "ylabel": "Steps",
160  "title": "Snapshot Level Monitoring: Memory Metrics",
161  "titleFontSize": 40,
162  "xlabelFontSize": 40,
163  "ylabelFontSize": 40,
164  "legendFontSize": 30
165  }
166 
167 
168  plotBarChart(timeMonParams)
169  plotBarChart(memMonParams)
170 
171 
172  timeMonFig.set_tight_layout( True )
173  timeMonFig.savefig("Snaphot_Level_Time")
174 
175  memMonFig.set_tight_layout(True)
176  memMonFig.savefig("Snapshot_Level_Memory")
177 
178 
179 def plotComponentLevel(componentLevelData, compCountPerPlot):
180 
181  timeMonFig = plt.figure(figsize=(35,105))
182  memMonFig = plt.figure(figsize=(35,105))
183 
184  for idx, step in enumerate(componentLevelData):
185 
186  compNames, vmemVals, cpuTimeVals, wallTimeVals, mallocVals, countVals = [],[],[],[],[],[]
187  for comp, meas in componentLevelData[step].items():
188 
189  count = meas["count"]
190  cpuTime = meas["cpuTime"] * 0.001 # seconds
191  wallTime = meas["wallTime"] * 0.001 # seconds
192  malloc = meas["malloc"] * 0.001 # MB
193  vmem = meas["vmem"] * 0.001 # MB
194 
195  # Discard negative measurements
196  if vmem < 0 or malloc < 0:
197  continue
198 
199  # Truncate unwieldy component names
200  if len(comp) > 50:
201  comp = f"{comp[:20]}[...]{comp[-20:]}"
202 
203  compNames.append(comp + " [" + str(count) + "]")
204  vmemVals.append(vmem)
205  cpuTimeVals.append(cpuTime)
206  wallTimeVals.append(wallTime)
207  mallocVals.append(malloc)
208  countVals.append(count)
209 
210  timeMonVals = {
211  "cpuTime": cpuTimeVals,
212  "wallTime": wallTimeVals
213  }
214 
215  memMonVals = {
216  "vmem": vmemVals,
217  "malloc": mallocVals,
218  }
219 
220  # Sort the components
221  sortedTimeMonCompNames, sortedTimeMonVals = sortComponents(compNames, timeMonVals, compCountPerPlot)
222  sortedCompNamesMem, sortedMemMonVals = sortComponents(compNames, memMonVals, compCountPerPlot)
223 
224  timeMonAx = timeMonFig.add_subplot(len(componentLevelData),1,idx+1)
225  memMonAx = memMonFig.add_subplot(len(componentLevelData),1,idx+1)
226 
227  timeMonParams = {
228  "ax": timeMonAx,
229  "index": np.arange(len(sortedTimeMonCompNames)),
230  "width": 0.5/len(sortedTimeMonVals), # Think about this
231  "vals": sortedTimeMonVals,
232  "yTickLabels": sortedTimeMonCompNames,
233  "xlabel": "Time [sec]",
234  "ylabel": "Components",
235  "title": step,
236  "titleFontSize": 70,
237  "xlabelFontSize": 50,
238  "ylabelFontSize": 50,
239  "legendFontSize": 30
240  }
241 
242  memMonParams = {
243  "ax": memMonAx,
244  "index": np.arange(len(sortedCompNamesMem)),
245  "width": 0.5/len(sortedMemMonVals), # Think about this
246  "vals": sortedMemMonVals,
247  "yTickLabels": sortedCompNamesMem,
248  "xlabel": "Memory [MB]",
249  "ylabel": "Components",
250  "title": step,
251  "titleFontSize": 70,
252  "xlabelFontSize": 50,
253  "ylabelFontSize": 50,
254  "legendFontSize": 30
255  }
256 
257  plotBarChart(timeMonParams)
258  plotBarChart(memMonParams)
259 
260  timeMonFig.set_tight_layout( True )
261  timeMonFig.savefig("Component_Level_Time")
262 
263  memMonFig.set_tight_layout( True )
264  memMonFig.savefig("Component_Level_Memory")
265 
266 
267 def plotEventLevel(eventLevelData):
268 
269  sortedEventLevelData = sorted(eventLevelData.items(), key=lambda i: int(i[0]))
270 
271  eventVals, cpuTimeVals, wallTimeVals, vmemVals, rssVals, pssVals, swapVals = [], [], [], [], [], [], []
272 
273  timeMonFig, timeMonAx = plt.subplots()
274  memMonFig, memMonAx = plt.subplots()
275 
276  for entry in sortedEventLevelData:
277 
278  event = entry[0]
279  meas = entry[1]
280 
281  # Time metrics in seconds, Memory metrics in megabytes
282  eventVals.append(event)
283  cpuTimeVals.append(meas['cpuTime'] * 0.001)
284  wallTimeVals.append(meas['wallTime'] * 0.001)
285  vmemVals.append(meas['vmem'] * 0.001)
286  rssVals.append(meas['rss'] * 0.001)
287  pssVals.append(meas['pss'] * 0.001)
288  swapVals.append(meas['swap'] * 0.001)
289 
290 
291  timeMonVals = {
292  "cpuTime": cpuTimeVals,
293  "wallTime": wallTimeVals
294  }
295 
296  memMonVals = {
297  "vmem": vmemVals,
298  "rss": rssVals,
299  "pss": pssVals,
300  "swap": swapVals
301  }
302 
303  timeMonParams = {
304  "ax": timeMonAx,
305  "yVals": timeMonVals,
306  "xVals": eventVals, # Maybe x ticks?
307  "xlabel": "Events",
308  "ylabel": "Time [sec]",
309  "title": "Event Level Time Measurements"
310  }
311 
312  memMonParams = {
313  "ax": memMonAx,
314  "yVals": memMonVals,
315  "xVals": eventVals, # Maybe x ticks?
316  "xlabel": "Events",
317  "ylabel": "Memory [MB]",
318  "title": "Event Level Memory Measurements"
319  }
320 
321 
322  plotLineChart(timeMonParams)
323  plotLineChart(memMonParams)
324 
325  timeMonFig.set_tight_layout(True)
326  timeMonFig.savefig("Event_Level_Time")
327 
328  memMonFig.set_tight_layout(True)
329  memMonFig.savefig("Event_Level_Memory")
330 
331 def process(data, ncomps):
332  if "snapshotLevel" in data["summary"]:
333  snapshotData = data["summary"]["snapshotLevel"]
334  plotSnapshotLevel(snapshotData, 'snapshotLevel.pdf')
335 
336  if "componentLevel" in data:
337  componentLevelData = data["componentLevel"]
338  plotComponentLevel(componentLevelData, ncomps)
339 
340  if "eventLevel" in data:
341  eventLevelData = data["eventLevel"]
342  plotEventLevel(eventLevelData)
343 
344 def main():
345  ''' Main function for producing plots from PerfMonMT JSON file.'''
346 
347  parser = argparse.ArgumentParser()
348 
349  parser.add_argument("-i", "--input", dest = "input",
350  default = 'PerfMonMTSvc_result.json',
351  help = 'The input JSON file')
352  parser.add_argument("-n", "--numberOfCompsPerPlot",
353  dest = "numberOfCompsPerPlot", default = 20,
354  help = "The number of components to be plotted")
355 
356  args = parser.parse_args()
357 
358  if tarfile.is_tarfile(args.input):
359  tar = tarfile.open(args.input)
360  for member in tar.getmembers():
361  f = tar.extractfile(member)
362  data = json.load(f)
363  process(data, int(args.numberOfCompsPerPlot))
364  tar.close()
365  else:
366  with open(args.input) as jsonFile:
367  data = json.load(jsonFile)
368  process(data, int(args.numberOfCompsPerPlot))
369 
370 
371 if __name__ == "__main__":
372  main()
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
perfmonmt-plotter.plotBarChart
def plotBarChart(params)
Definition: perfmonmt-plotter.py:28
perfmonmt-plotter.plotComponentLevel
def plotComponentLevel(componentLevelData, compCountPerPlot)
Definition: perfmonmt-plotter.py:179
dumpHVPathFromNtuple.append
bool append
Definition: dumpHVPathFromNtuple.py:91
perfmonmt-plotter.plotEventLevel
def plotEventLevel(eventLevelData)
Definition: perfmonmt-plotter.py:267
convertTimingResiduals.sum
sum
Definition: convertTimingResiduals.py:55
perfmonmt-plotter.process
def process(data, ncomps)
Definition: perfmonmt-plotter.py:331
DerivationFramework::TriggerMatchingUtils::sorted
std::vector< typename T::value_type > sorted(T begin, T end)
Helper function to create a sorted vector from an unsorted one.
perfmonmt-plotter.plotLineChart
def plotLineChart(params)
Definition: perfmonmt-plotter.py:49
TrigJetMonitorAlgorithm.items
items
Definition: TrigJetMonitorAlgorithm.py:79
Trk::open
@ open
Definition: BinningType.h:40
perfmonmt-plotter.sortComponents
def sortComponents(compNames, measDict, compCountPerPlot)
Definition: perfmonmt-plotter.py:66
perfmonmt-plotter.plotSnapshotLevel
def plotSnapshotLevel(snapshotData, plotname)
Definition: perfmonmt-plotter.py:94
perfmonmt-plotter.main
def main()
Definition: perfmonmt-plotter.py:344
str
Definition: BTagTrackIpAccessor.cxx:11