xref: /libCEED/benchmarks/postprocess_plot.py (revision d13e9b485390d2a242cbc549de647bb7b44f1cad)
1#!/usr/bin/env python3
2# Copyright (c) 2017-2018, Lawrence Livermore National Security, LLC.
3# Produced at the Lawrence Livermore National Laboratory. LLNL-CODE-734707.
4# All Rights reserved. See files LICENSE and NOTICE for details.
5#
6# This file is part of CEED, a collection of benchmarks, miniapps, software
7# libraries and APIs for efficient high-order finite element and spectral
8# element discretizations for exascale applications. For more information and
9# source code availability see http://github.com/ceed.
10#
11# The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
12# a collaborative effort of two U.S. Department of Energy organizations (Office
13# of Science and the National Nuclear Security Administration) responsible for
14# the planning and preparation of a capable exascale ecosystem, including
15# software, applications, hardware, advanced system engineering and early
16# testbed platforms, in support of the nation's exascale computing imperative.
17
18
19#####   Adjustable plot parameters:
20log_y=0               # use log scale on the y-axis?
21x_range=(1e1,4e6)     # plot range for the x-axis; comment out for auto
22y_range=(0,2e9)       # plot range for the y-axis; comment out for auto
23draw_iter_lines=0     # draw the "iter/s" lines?
24ymin_iter_lines=3e5   # minimal y value for the "iter/s" lines
25ymax_iter_lines=8e8   # maximal y value for the "iter/s" lines
26legend_ncol=(2 if log_y else 1)   # number of columns in the legend
27write_figures=1       # save the figures to files?
28show_figures=1        # display the figures on the screen?
29
30
31#####   Load the data
32import pandas as pd
33from postprocess_base import read_logs
34
35runs = read_logs()
36
37#####   Sample plot output
38from matplotlib import use
39if not show_figures:
40   use('pdf')
41from pylab import *
42
43rcParams['font.sans-serif'].insert(0,'Noto Sans')
44rcParams['font.sans-serif'].insert(1,'Open Sans')
45rcParams['figure.figsize']=[10, 8] # default: 8 x 6
46
47cm_size=16
48colors=['dimgrey','black','saddlebrown','firebrick','red','orange',
49        'gold','lightgreen','green','cyan','teal','blue','navy',
50        'purple','magenta','pink']
51
52##### Get test names
53sel_runs=runs
54tests=list(sel_runs.test.unique())
55test=tests[0]
56
57##### Run information
58print('Using test:', test)
59
60if 'CEED Benchmark Problem' in test:
61   test_short = test.strip().split()[0] + ' BP' + test.strip().split()[-1]
62
63##### Plot same BP
64sel_runs=sel_runs.loc[sel_runs['test'] == test]
65
66##### Plot same case (scalar vs vector)
67cases=list(sel_runs.case.unique())
68case=cases[0]
69vdim=1 if case=='scalar' else 3
70print('Using case:', case)
71sel_runs=sel_runs.loc[sel_runs['case'] == case]
72
73##### Plot same 'code'
74codes = list(sel_runs.code.unique())
75code  = codes[0]
76sel_runs=sel_runs.loc[sel_runs['code'] == code]
77
78##### Group plots by backend and number of processes
79pl_set=sel_runs[['backend', 'backend_memtype', 'num_procs', 'num_procs_node']]
80pl_set=pl_set.drop_duplicates()
81
82##### Plotting
83for index, row in pl_set.iterrows():
84   backend=row['backend']
85   backend_memtype=row['backend_memtype']
86   num_procs=float(row['num_procs'])
87   num_procs_node=float(row['num_procs_node'])
88   num_nodes=num_procs/num_procs_node
89   pl_runs=sel_runs[(sel_runs.backend==backend) |
90                    (sel_runs.num_procs==num_procs) |
91                    (sel_runs.num_procs_node==num_procs_node)]
92   if len(pl_runs.index)==0:
93      continue
94
95   print('backend: %s, compute nodes: %i, number of MPI tasks = %i'%(
96      backend,num_nodes,num_procs))
97
98   figure()
99   i=0
100   sol_p_set=sel_runs['degree'].drop_duplicates()
101   sol_p_set=sol_p_set.sort_values()
102   ##### Iterate over P
103   for sol_p in sol_p_set:
104      qpts=sel_runs['quadrature_pts'].loc[pl_runs['degree']==sol_p]
105      qpts=qpts.drop_duplicates().sort_values(ascending=False)
106      qpts=qpts.reset_index(drop=True)
107      print('Degree: %i, quadrature points:'%sol_p, qpts[0])
108      # Generate plot data
109      d=[[run['degree'],run['num_elem'],1.*run['num_unknowns']/num_nodes/vdim,
110          run['cg_iteration_dps']/num_nodes]
111         for index, run in
112         pl_runs.loc[(pl_runs['degree']==sol_p) |
113                     (pl_runs['quadrature_pts']==qpts[0])].iterrows()]
114      d=[[e[2],e[3]] for e in d if e[0]==sol_p]
115      # (DOFs/[sec/iter]/node)/(DOFs/node) = iter/sec
116      d=[[nun,
117          min([e[1] for e in d if e[0]==nun]),
118          max([e[1] for e in d if e[0]==nun])]
119         for nun in set([e[0] for e in d])]
120      d=asarray(sorted(d))
121      # Plot
122      plot(d[:,0],d[:,2],'o-',color=colors[i%cm_size],
123           label='p=%i'%sol_p)
124      if list(d[:,1]) != list(d[:,2]):
125         plot(d[:,0],d[:,1],'o-',color=colors[i])
126         fill_between(d[:,0],d[:,1],d[:,2],facecolor=colors[i],alpha=0.2)
127      # Continue if only 1 set of qpts
128      if len(qpts)==1:
129         i=i+1
130         continue
131      # Second set of qpts
132      d=[[run['degree'],run['num_elem'],1.*run['num_unknowns']/num_nodes/vdim,
133          run['cg_iteration_dps']/num_nodes]
134         for index, run in
135         pl_runs.loc[(pl_runs['degree']==sol_p) |
136                     (pl_runs['quadrature_pts']==qpts[1])].iterrows()]
137      d=[[e[2],e[3]] for e in d if e[0]==sol_p]
138      if len(d)==0:
139         i=i+1
140         continue
141      d=[[nun,
142          min([e[1] for e in d if e[0]==nun]),
143          max([e[1] for e in d if e[0]==nun])]
144         for nun in set([e[0] for e in d])]
145      d=asarray(sorted(d))
146      plot(d[:,0],d[:,2],'s--',color=colors[i],
147           label='p=%i'%sol_p)
148      if list(d[:,1]) != list(d[:,2]):
149         plot(d[:,0],d[:,1],'s--',color=colors[i])
150      ##
151      i=i+1
152   ##
153   if draw_iter_lines:
154      y0,y1=ymin_iter_lines,ymax_iter_lines
155      y=asarray([y0,y1]) if log_y else exp(linspace(log(y0), log(y1)))
156      slope1=600.
157      slope2=6000.
158      plot(y/slope1,y,'k--',label='%g iter/s'%(slope1/vdim))
159      plot(y/slope2,y,'k-',label='%g iter/s'%(slope2/vdim))
160
161   # Plot information
162   title(r'%i node%s $\times$ %i ranks, %s, %s, %s'%(
163         num_nodes,'' if num_nodes==1 else 's',
164         num_procs_node,backend,backend_memtype,test_short),fontsize=16)
165   xscale('log') # subsx=[2,4,6,8]
166   if log_y:
167      yscale('log')
168   if 'x_range' in vars() and len(x_range)==2:
169      xlim(x_range)
170   if 'y_range' in vars() and len(y_range)==2:
171      ylim(y_range)
172   grid('on', color='gray', ls='dotted')
173   grid('on', axis='both', which='minor', color='gray', ls='dotted')
174   plt.tick_params(labelsize=14)
175   exptext = gca().yaxis.get_offset_text()
176   exptext.set_size(14)
177   gca().set_axisbelow(True)
178   xlabel('Points per compute node',fontsize=14)
179   ylabel('[DOFs x CG iterations] / [compute nodes x seconds]',fontsize=14)
180   legend(ncol=legend_ncol, loc='best',fontsize=13)
181
182   # Write
183   if write_figures: # write .pdf file?
184      short_backend=backend.replace('/','')
185      test_short_save=test_short.replace(' ','')
186      pdf_file='plot_%s_%s_%s_%s_N%03i_pn%i.pdf'%(
187               code,test_short_save,short_backend,backend_memtype,num_nodes,num_procs_node)
188      print('\nsaving figure --> %s'%pdf_file)
189      savefig(pdf_file, format='pdf', bbox_inches='tight')
190
191if show_figures: # show the figures?
192   print('\nShowing figures ...')
193   show()
194