10from matplotlib
import pyplot
as plt
11from matplotlib.projections.polar
import PolarAxes
12from matplotlib.projections
import register_projection
15Read the stats file produced by the OpenMP runtime
16and produce a processed summary
18The radar_factory original code was taken from
19matplotlib.org/examples/api/radar_chart.html
20We added support to handle negative values for radar charts
24 """Create a radar chart with num_vars axes."""
26 theta = 2*np.pi * np.linspace(0, 1-1./num_vars, num_vars)
30 def draw_poly_frame(self, x0, y0, r):
32 verts = [(r*np.cos(t) + x0, r*np.sin(t) + y0)
for t
in theta]
33 return plt.Polygon(verts, closed=
True, edgecolor=
'k')
35 def draw_circle_frame(self, x0, y0, r):
36 return plt.Circle((x0, y0), r)
38 frame_dict = {
'polygon': draw_poly_frame,
'circle': draw_circle_frame}
39 if frame
not in frame_dict:
40 raise ValueError,
'unknown value for `frame`: %s' % frame
42 class RadarAxes(PolarAxes):
44 Class for creating a radar chart (a.k.a. a spider
or star chart)
46 http://en.wikipedia.org/wiki/Radar_chart
52 draw_frame = frame_dict[frame]
54 def fill(self, *args, **kwargs):
55 """Override fill so that line is closed by default"""
56 closed = kwargs.pop(
'closed',
True)
57 return super(RadarAxes, self).fill(closed=closed, *args, **kwargs)
59 def plot(self, *args, **kwargs):
60 """Override plot so that line is closed by default"""
61 lines = super(RadarAxes, self).plot(*args, **kwargs)
65 def set_varlabels(self, labels):
66 self.set_thetagrids(theta * 180/np.pi, labels,fontsize=14)
68 def _gen_axes_patch(self):
71 return self.draw_frame(x0, y0, r)
73 register_projection(RadarAxes)
78 """Convert a measurement with a range suffix into a suitably scaled value"""
81 units = du[1]
if len(du) == 2
else ' '
105 return num*factor
if factor > 0
else num/-factor
109 fieldnames = [x.strip()
for x
in line.split(
',')]
110 line = f.readline().strip()
114 fields = line.split(
',')
115 data.append ((fields[0].strip(), [
extractSI(v)
for v
in fields[1:]]))
116 line = f.readline().strip()
120 res = pd.DataFrame.from_items(data, columns=fieldnames[1:], orient=
'index')
124 """Skip lines with leading #"""
126 while line[0] ==
'#':
129 if line ==
"Statistics on exit\n" or "Aggregate for all threads\n":
134 """This can be just the same!"""
138 """Read the statistics from the file. Return a dict with keys "timers", "counters" """
141 with open(fname)
as f:
145 except (OSError, IOError):
146 print "Cannot open " + fname
150 """I.e. values which are neither null nor zero"""
151 return [p
and q
for (p,q)
in zip (pd.notnull(l), l != 0.0)]
154 """I.e. values which are null or zero"""
157interestingStats = (
"counters",
"timers")
158statProperties = {
"counters" : (
"Count",
"Counter Statistics"),
159 "timers" : (
"Time (ticks)",
"Timer Statistics")
163 """Draw a summary bar chart for the requested data frame into the specified file"""
164 data[
"Mean"].plot(kind=
"bar", logy=
True, grid=
True, colormap=
"GnBu",
165 yerr=data[
"SD"], ecolor=
"black")
166 plt.xlabel(
"OMP Constructs")
167 plt.ylabel(statProperties[kind][0])
168 plt.title (statProperties[kind][1])
170 plt.savefig(filebase+
"_"+kind)
173 """Normalize values into a rate by dividing them all by the given factor"""
174 data[[k for k
in data.keys()
if k != countField]] /= factor
178 """Set the attributes for the radar plots"""
179 fig = plt.figure(figsize=(9,9))
180 rect = [0.1, 0.1, 0.8, 0.8]
181 labels = [0.2, 0.4, 0.6, 0.8, 1, 2, 3, 4, 5, 10]
182 matplotlib.rcParams.update({
'font.size':13})
184 ax = fig.add_axes(rect, projection=
'radar')
185 ax.set_rgrids(labels)
186 ax.set_varlabels(titles)
187 ax.text(theta[2], 1,
"Linear->Log", horizontalalignment=
'center', color=
'green', fontsize=18)
188 return {
'ax':ax,
'theta':theta}
192 """Draw the radar plots"""
195 for key
in data.keys():
197 tmp_log[key] = np.log10(data[key])
199 tmp_lin[key] = (data[key])
200 params[
'ax'].plot(params[
'theta'], tmp_log, color=
'b', label=filebase+
"_"+kind+
"_log")
201 params[
'ax'].plot(params[
'theta'], tmp_lin, color=
'r', label=filebase+
"_"+kind+
"_linear")
202 params[
'ax'].legend(loc=
'best', bbox_to_anchor=(1.4,1.2))
203 params[
'ax'].set_rlim((0, np.ceil(max(tmp_log))))
208 ax.set_xticks(index + width * n / 2)
209 ax.set_xticklabels(tmp[s][
'Total'].keys(), rotation=50, horizontalalignment=
'right')
210 plt.xlabel(
"OMP Constructs")
211 plt.ylabel(statProperties[s][0])
212 plt.title(statProperties[s][1])
217 for key
in data.keys():
218 if key ==
'OMP_worker_thread_life':
219 totalRuntime = data[
'OMP_worker_thread_life']
220 elif key
in (
'FOR_static_iterations',
'OMP_PARALLEL_args',
221 'OMP_set_numthreads',
'FOR_dynamic_iterations'):
224 stats[key] = 100 * data[key] / totalRuntime
230 for key
in data.keys():
231 if key
in (
'OMP_critical',
'OMP_single',
'OMP_serial',
232 'OMP_parallel',
'OMP_master',
'OMP_task_immediate',
233 'OMP_task_taskwait',
'OMP_task_taskyield',
'OMP_task_taskgroup',
234 'OMP_task_join_bar',
'OMP_task_plain_bar',
'OMP_task_taskyield'):
235 compKeys[key] = data[key]
237 nonCompKeys[key] = data[key]
238 print "comp keys:", compKeys,
"\n\n non comp keys:", nonCompKeys
239 return [compKeys, nonCompKeys]
242 sizes = [
sum(data[0].values()),
sum(data[1].values())]
244 labels = [
"Compute - " +
"%.2f" % sizes[0],
"Non Compute - " +
"%.2f" % sizes[1]]
245 patches = plt.pie(sizes, explode, colors=colors, startangle=90)
246 plt.title(
"Time Division")
248 plt.legend(patches[0], labels, loc=
'best', bbox_to_anchor=(-0.1,1), fontsize=16)
249 plt.savefig(filebase+
"_main_pie", bbox_inches=
'tight')
254 sizes = data.values()
257 for i
in range(len(sizes)):
259 percent.append(100 * sizes[i] / total)
260 labels[i] = labels[i] +
" - %.2f" % percent[i]
261 patches = plt.pie(sizes, explode=explode, colors=colors, startangle=90)
262 plt.title(tag+
"(Percentage of Total:"+
" %.2f" % (
sum(data.values()))+
")")
265 plt.legend(patches[0], labels, loc=
'best', bbox_to_anchor=(-0.1,1), fontsize=16)
266 plt.savefig(filebase+
"_"+tag, bbox_inches=
'tight')
269 parser = argparse.ArgumentParser(description=
'''This script takes a list
270 of files containing each of which contain output from a stats-gathering
271 enabled OpenMP runtime library. Each stats file
is read, parsed,
and
272 used to produce a summary of the statistics
''')
273 parser.add_argument('files', nargs=
'+',
274 help=
'files to parse which contain stats-gathering output')
275 command_args = parser.parse_args()
276 colors = [
'orange',
'b',
'r',
'yellowgreen',
'lightsage',
'lightpink',
277 'green',
'purple',
'yellow',
'cyan',
'mediumturquoise',
280 matplotlib.rcParams.update({
'font.size':22})
281 for s
in interestingStats:
282 fig, ax = plt.subplots()
287 for f
in command_args.files:
288 filebase = os.path.splitext(f)[0]
290 data = tmp[s][
'Total']
291 """preventing repetition by removing rows similar to Total_OMP_work
292 as Total_OMP_work[
'Total']
is same
as OMP_work[
'Total']
"""
294 elapsedTime = tmp[
"timers"][
"Mean"][
"OMP_worker_thread_life"]
297 """Plotting radar charts"""
301 """radar Charts finish here"""
302 plt.savefig(filebase+
"_"+s+
"_"+chartType, bbox_inches=
'tight')
304 print "overheads in "+filebase
305 numThreads = tmp[s][
'SampleCount'][
'Total_OMP_parallel']
306 for key
in data.keys():
307 if key[0:5] ==
'Total':
310 dataSubSet =
compPie(stats[filebase])
313 drawSubPie(dataSubSet[0],
"Computational Time", filebase, colors)
315 drawSubPie(dataSubSet[1],
"Non Computational Time", filebase, colors)
316 with open(
'derivedStats_{}.csv'.format(filebase),
'w')
as f:
317 f.write(
'================={}====================\n'.format(filebase))
318 f.write(pd.DataFrame(stats[filebase].items()).to_csv()+
'\n')
322if __name__ ==
"__main__":
def radar_factory(num_vars, frame='circle')
def derivedTimerStats(data)
def setRadarFigure(titles)
def drawChart(data, kind, filebase)
def drawSubPie(data, tag, filebase, colors)
def drawMainPie(data, filebase, colors)
def normalizeValues(data, countField, factor)
def drawRadarChart(data, kind, filebase, params, color)
def multiAppBarChartSettings(ax, plt, index, width, n, tmp, s)