1d13e9b48SJed Brown#!/usr/bin/env python3 25cd6c1fbSSebastian Grimberg 3*5aed82e4SJeremy L Thompson# Copyright (c) 2017-2024, Lawrence Livermore National Security, LLC and other CEED contributors. 4*5aed82e4SJeremy L Thompson# All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 5d13e9b48SJed Brown# 6*5aed82e4SJeremy L Thompson# SPDX-License-Identifier: BSD-2-Clause 7d13e9b48SJed Brown# 8*5aed82e4SJeremy L Thompson# This file is part of CEED: http://github.com/ceed 9d13e9b48SJed Brown 10dec49e00SJed Brownfrom pylab import * 11dec49e00SJed Brownfrom matplotlib import use 12dec49e00SJed Brownfrom postprocess_base import read_logs 13dec49e00SJed Brownimport pandas as pd 145cd6c1fbSSebastian Grimberg 155cd6c1fbSSebastian Grimberg# Adjustable plot parameters 16d13e9b48SJed Brownlog_y = 0 # use log scale on the y-axis? 17d13e9b48SJed Brownx_range = (1e1, 4e6) # plot range for the x-axis; comment out for auto 18d13e9b48SJed Browny_range = (0, 2e9) # plot range for the y-axis; comment out for auto 19d13e9b48SJed Browndraw_iter_lines = 0 # draw the "iter/s" lines? 20d13e9b48SJed Brownymin_iter_lines = 3e5 # minimal y value for the "iter/s" lines 21d13e9b48SJed Brownymax_iter_lines = 8e8 # maximal y value for the "iter/s" lines 22d13e9b48SJed Brownlegend_ncol = (2 if log_y else 1) # number of columns in the legend 23d13e9b48SJed Brownwrite_figures = 1 # save the figures to files? 24d13e9b48SJed Brownshow_figures = 1 # display the figures on the screen? 25d13e9b48SJed Brown 26dec49e00SJed Brown# Load the data 27d13e9b48SJed Brownruns = read_logs() 28d13e9b48SJed Brown 29dec49e00SJed Brown# Sample plot output 30d13e9b48SJed Brownif not show_figures: 31d13e9b48SJed Brown use('pdf') 32d13e9b48SJed Brown 33d13e9b48SJed BrownrcParams['font.sans-serif'].insert(0, 'Noto Sans') 34d13e9b48SJed BrownrcParams['font.sans-serif'].insert(1, 'Open Sans') 35d13e9b48SJed BrownrcParams['figure.figsize'] = [10, 8] # default: 8 x 6 36d13e9b48SJed Brown 37d13e9b48SJed Browncm_size = 16 38d13e9b48SJed Browncolors = ['dimgrey', 'black', 'saddlebrown', 'firebrick', 'red', 'orange', 39d13e9b48SJed Brown 'gold', 'lightgreen', 'green', 'cyan', 'teal', 'blue', 'navy', 40d13e9b48SJed Brown 'purple', 'magenta', 'pink'] 41d13e9b48SJed Brown 42dec49e00SJed Brown# Get test names 43d13e9b48SJed Brownsel_runs = runs 44d13e9b48SJed Browntests = list(sel_runs.test.unique()) 45d13e9b48SJed Browntest = tests[0] 46d13e9b48SJed Brown 47dec49e00SJed Brown# Run information 48d13e9b48SJed Brownprint('Using test:', test) 49d13e9b48SJed Brown 50d13e9b48SJed Brownif 'CEED Benchmark Problem' in test: 51d13e9b48SJed Brown test_short = test.strip().split()[0] + ' BP' + test.strip().split()[-1] 52d13e9b48SJed Brown 53dec49e00SJed Brown# Plot same BP 54d13e9b48SJed Brownsel_runs = sel_runs.loc[sel_runs['test'] == test] 55d13e9b48SJed Brown 56dec49e00SJed Brown# Plot same case (scalar vs vector) 57d13e9b48SJed Browncases = list(sel_runs.case.unique()) 58d13e9b48SJed Browncase = cases[0] 59d13e9b48SJed Brownvdim = 1 if case == 'scalar' else 3 60d13e9b48SJed Brownprint('Using case:', case) 61d13e9b48SJed Brownsel_runs = sel_runs.loc[sel_runs['case'] == case] 62d13e9b48SJed Brown 63dec49e00SJed Brown# Plot same 'code' 64d13e9b48SJed Browncodes = list(sel_runs.code.unique()) 65d13e9b48SJed Browncode = codes[0] 66d13e9b48SJed Brownsel_runs = sel_runs.loc[sel_runs['code'] == code] 67d13e9b48SJed Brown 68dec49e00SJed Brown# Group plots by backend and number of processes 69981e58aeSvaleriabarrapl_set = sel_runs[['backend', 70981e58aeSvaleriabarra 'backend_memtype', 71981e58aeSvaleriabarra 'num_procs', 72981e58aeSvaleriabarra 'num_procs_node']] 73d13e9b48SJed Brownpl_set = pl_set.drop_duplicates() 74d13e9b48SJed Brown 75dec49e00SJed Brown# Plotting 76d13e9b48SJed Brownfor index, row in pl_set.iterrows(): 77d13e9b48SJed Brown backend = row['backend'] 78d13e9b48SJed Brown backend_memtype = row['backend_memtype'] 79d13e9b48SJed Brown num_procs = float(row['num_procs']) 80d13e9b48SJed Brown num_procs_node = float(row['num_procs_node']) 81d13e9b48SJed Brown num_nodes = num_procs / num_procs_node 82d13e9b48SJed Brown pl_runs = sel_runs[(sel_runs.backend == backend) | 83d13e9b48SJed Brown (sel_runs.num_procs == num_procs) | 84d13e9b48SJed Brown (sel_runs.num_procs_node == num_procs_node)] 85d13e9b48SJed Brown if len(pl_runs.index) == 0: 86d13e9b48SJed Brown continue 87d13e9b48SJed Brown 88d13e9b48SJed Brown print('backend: %s, compute nodes: %i, number of MPI tasks = %i' % ( 89d13e9b48SJed Brown backend, num_nodes, num_procs)) 90d13e9b48SJed Brown 91d13e9b48SJed Brown figure() 92d13e9b48SJed Brown i = 0 93d13e9b48SJed Brown sol_p_set = sel_runs['degree'].drop_duplicates() 94d13e9b48SJed Brown sol_p_set = sol_p_set.sort_values() 95dec49e00SJed Brown # Iterate over P 96d13e9b48SJed Brown for sol_p in sol_p_set: 97d13e9b48SJed Brown qpts = sel_runs['quadrature_pts'].loc[pl_runs['degree'] == sol_p] 98d13e9b48SJed Brown qpts = qpts.drop_duplicates().sort_values(ascending=False) 99d13e9b48SJed Brown qpts = qpts.reset_index(drop=True) 100d13e9b48SJed Brown print('Degree: %i, quadrature points:' % sol_p, qpts[0]) 101d13e9b48SJed Brown # Generate plot data 102d13e9b48SJed Brown d = [[run['degree'], run['num_elem'], 1. * run['num_unknowns'] / num_nodes / vdim, 103d13e9b48SJed Brown run['cg_iteration_dps'] / num_nodes] 104d13e9b48SJed Brown for index, run in 105d13e9b48SJed Brown pl_runs.loc[(pl_runs['degree'] == sol_p) | 106d13e9b48SJed Brown (pl_runs['quadrature_pts'] == qpts[0])].iterrows()] 107d13e9b48SJed Brown d = [[e[2], e[3]] for e in d if e[0] == sol_p] 108d13e9b48SJed Brown # (DOFs/[sec/iter]/node)/(DOFs/node) = iter/sec 109d13e9b48SJed Brown d = [[nun, 110d13e9b48SJed Brown min([e[1] for e in d if e[0] == nun]), 111d13e9b48SJed Brown max([e[1] for e in d if e[0] == nun])] 112d13e9b48SJed Brown for nun in set([e[0] for e in d])] 113d13e9b48SJed Brown d = asarray(sorted(d)) 114d13e9b48SJed Brown # Plot 115d13e9b48SJed Brown plot(d[:, 0], d[:, 2], 'o-', color=colors[i % cm_size], 116d13e9b48SJed Brown label='p=%i' % sol_p) 117d13e9b48SJed Brown if list(d[:, 1]) != list(d[:, 2]): 118d13e9b48SJed Brown plot(d[:, 0], d[:, 1], 'o-', color=colors[i]) 119dec49e00SJed Brown fill_between(d[:, 0], d[:, 1], d[:, 2], 120dec49e00SJed Brown facecolor=colors[i], alpha=0.2) 121d13e9b48SJed Brown # Continue if only 1 set of qpts 122d13e9b48SJed Brown if len(qpts) == 1: 123d13e9b48SJed Brown i = i + 1 124d13e9b48SJed Brown continue 125d13e9b48SJed Brown # Second set of qpts 126d13e9b48SJed Brown d = [[run['degree'], run['num_elem'], 1. * run['num_unknowns'] / num_nodes / vdim, 127d13e9b48SJed Brown run['cg_iteration_dps'] / num_nodes] 128d13e9b48SJed Brown for index, run in 129d13e9b48SJed Brown pl_runs.loc[(pl_runs['degree'] == sol_p) | 130d13e9b48SJed Brown (pl_runs['quadrature_pts'] == qpts[1])].iterrows()] 131d13e9b48SJed Brown d = [[e[2], e[3]] for e in d if e[0] == sol_p] 132d13e9b48SJed Brown if len(d) == 0: 133d13e9b48SJed Brown i = i + 1 134d13e9b48SJed Brown continue 135d13e9b48SJed Brown d = [[nun, 136d13e9b48SJed Brown min([e[1] for e in d if e[0] == nun]), 137d13e9b48SJed Brown max([e[1] for e in d if e[0] == nun])] 138d13e9b48SJed Brown for nun in set([e[0] for e in d])] 139d13e9b48SJed Brown d = asarray(sorted(d)) 140d13e9b48SJed Brown plot(d[:, 0], d[:, 2], 's--', color=colors[i], 141d13e9b48SJed Brown label='p=%i' % sol_p) 142d13e9b48SJed Brown if list(d[:, 1]) != list(d[:, 2]): 143d13e9b48SJed Brown plot(d[:, 0], d[:, 1], 's--', color=colors[i]) 144d13e9b48SJed Brown ## 145d13e9b48SJed Brown i = i + 1 146d13e9b48SJed Brown ## 147d13e9b48SJed Brown if draw_iter_lines: 148d13e9b48SJed Brown y0, y1 = ymin_iter_lines, ymax_iter_lines 149d13e9b48SJed Brown y = asarray([y0, y1]) if log_y else exp(linspace(log(y0), log(y1))) 150d13e9b48SJed Brown slope1 = 600. 151d13e9b48SJed Brown slope2 = 6000. 152d13e9b48SJed Brown plot(y / slope1, y, 'k--', label='%g iter/s' % (slope1 / vdim)) 153d13e9b48SJed Brown plot(y / slope2, y, 'k-', label='%g iter/s' % (slope2 / vdim)) 154d13e9b48SJed Brown 155d13e9b48SJed Brown # Plot information 156d13e9b48SJed Brown title(r'%i node%s $\times$ %i ranks, %s, %s, %s' % ( 157d13e9b48SJed Brown num_nodes, '' if num_nodes == 1 else 's', 158d13e9b48SJed Brown num_procs_node, backend, backend_memtype, test_short), fontsize=16) 159d13e9b48SJed Brown xscale('log') # subsx=[2,4,6,8] 160d13e9b48SJed Brown if log_y: 161d13e9b48SJed Brown yscale('log') 162d13e9b48SJed Brown if 'x_range' in vars() and len(x_range) == 2: 163d13e9b48SJed Brown xlim(x_range) 164d13e9b48SJed Brown if 'y_range' in vars() and len(y_range) == 2: 165d13e9b48SJed Brown ylim(y_range) 166d13e9b48SJed Brown grid('on', color='gray', ls='dotted') 167d13e9b48SJed Brown grid('on', axis='both', which='minor', color='gray', ls='dotted') 168d13e9b48SJed Brown plt.tick_params(labelsize=14) 169d13e9b48SJed Brown exptext = gca().yaxis.get_offset_text() 170d13e9b48SJed Brown exptext.set_size(14) 171d13e9b48SJed Brown gca().set_axisbelow(True) 172d13e9b48SJed Brown xlabel('Points per compute node', fontsize=14) 173d13e9b48SJed Brown ylabel('[DOFs x CG iterations] / [compute nodes x seconds]', fontsize=14) 174d13e9b48SJed Brown legend(ncol=legend_ncol, loc='best', fontsize=13) 175d13e9b48SJed Brown 176d13e9b48SJed Brown # Write 177d13e9b48SJed Brown if write_figures: # write .pdf file? 178d13e9b48SJed Brown short_backend = backend.replace('/', '') 179d13e9b48SJed Brown test_short_save = test_short.replace(' ', '') 180d13e9b48SJed Brown pdf_file = 'plot_%s_%s_%s_%s_N%03i_pn%i.pdf' % ( 181d13e9b48SJed Brown code, test_short_save, short_backend, backend_memtype, num_nodes, num_procs_node) 182d13e9b48SJed Brown print('\nsaving figure --> %s' % pdf_file) 183d13e9b48SJed Brown savefig(pdf_file, format='pdf', bbox_inches='tight') 184d13e9b48SJed Brown 185d13e9b48SJed Brownif show_figures: # show the figures? 186d13e9b48SJed Brown print('\nShowing figures ...') 187d13e9b48SJed Brown show() 188