1d13e9b48SJed Brown#!/usr/bin/env python3 25cd6c1fbSSebastian Grimberg 3*9ba83ac0SJeremy L Thompson# Copyright (c) 2017-2026, Lawrence Livermore National Security, LLC and other CEED contributors. 45aed82e4SJeremy L Thompson# All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 5d13e9b48SJed Brown# 65aed82e4SJeremy L Thompson# SPDX-License-Identifier: BSD-2-Clause 7d13e9b48SJed Brown# 85aed82e4SJeremy L Thompson# This file is part of CEED: http://github.com/ceed 9d13e9b48SJed Brown 105cd6c1fbSSebastian Grimberg# Read all input files specified on the command line, or stdin and parse 115cd6c1fbSSebastian Grimberg# the content, storing it as a pandas dataframe 125cd6c1fbSSebastian Grimberg 13d13e9b48SJed Brownimport pandas as pd 14d13e9b48SJed Brownimport fileinput 15d13e9b48SJed Brownimport pprint 16d13e9b48SJed Brown 17dec49e00SJed Brown 18d13e9b48SJed Browndef read_logs(files=None): 19aa2aa0aeSJed Brown """Read all input files and return pandas DataFrame""" 20aa2aa0aeSJed Brown data_default = dict( 21dd839fb7SJed Brown file='unknown', 22dd839fb7SJed Brown backend='unknown', 23aa2aa0aeSJed Brown backend_memtype='unknown', 24aa2aa0aeSJed Brown hostname='unknown', 25dd839fb7SJed Brown test='unknown', 26dd839fb7SJed Brown num_procs=0, 27dd839fb7SJed Brown num_procs_node=0, 28dd839fb7SJed Brown degree=0, 29dd839fb7SJed Brown quadrature_pts=0, 30dd839fb7SJed Brown code='libCEED', 31dd839fb7SJed Brown ) 32aa2aa0aeSJed Brown data = data_default.copy() 33dd839fb7SJed Brown 34d13e9b48SJed Brown runs = [] 35aa2aa0aeSJed Brown for line in fileinput.input(files): 36dec49e00SJed Brown # Legacy header contains number of MPI tasks 37dd839fb7SJed Brown if 'Running the tests using a total of' in line: 38aa2aa0aeSJed Brown data = data_default.copy() 39dec49e00SJed Brown data['num_procs'] = int( 40dec49e00SJed Brown line.split( 41dec49e00SJed Brown 'a total of ', 42dec49e00SJed Brown 1)[1].split( 43dec49e00SJed Brown None, 44dec49e00SJed Brown 1)[0]) 45dec49e00SJed Brown # MPI tasks per node 46d13e9b48SJed Brown elif 'tasks per node' in line: 47dec49e00SJed Brown data['num_procs_node'] = int( 48dec49e00SJed Brown line.split( 49dec49e00SJed Brown ' tasks per', 50dec49e00SJed Brown 1)[0].rsplit( 51dec49e00SJed Brown None, 52dec49e00SJed Brown 1)[1]) 53dec49e00SJed Brown # New Benchmark Problem 54d13e9b48SJed Brown elif "CEED Benchmark Problem" in line: 55dd839fb7SJed Brown # Starting a new block 56dd839fb7SJed Brown data = data.copy() 57dd839fb7SJed Brown runs.append(data) 58dd839fb7SJed Brown data['file'] = fileinput.filename() 59d13e9b48SJed Brown data['test'] = line.split()[-2] + " " + line.split('-- ')[1] 60aa2aa0aeSJed Brown data['bp'] = data['test'].rsplit()[-1] 61d13e9b48SJed Brown data['case'] = 'scalar' if (('Problem 1' in line) or ('Problem 3' in line) 62d13e9b48SJed Brown or ('Problem 5' in line)) else 'vector' 63dd839fb7SJed Brown elif "Hostname" in line: 64dd839fb7SJed Brown data['hostname'] = line.split(':')[1].strip() 65dd839fb7SJed Brown elif "Total ranks" in line: 66dd839fb7SJed Brown data['num_procs'] = int(line.split(':')[1].strip()) 67aa2aa0aeSJed Brown elif "Ranks per compute node" in line: 68dd839fb7SJed Brown data['num_procs_node'] = int(line.split(':')[1].strip()) 69dec49e00SJed Brown # Backend 70d13e9b48SJed Brown elif 'libCEED Backend MemType' in line: 71d13e9b48SJed Brown data['backend_memtype'] = line.split(':')[1].strip() 72d13e9b48SJed Brown elif 'libCEED Backend' in line: 73d13e9b48SJed Brown data['backend'] = line.split(':')[1].strip() 74dec49e00SJed Brown # P 75d13e9b48SJed Brown elif 'Basis Nodes' in line: 76d13e9b48SJed Brown data['degree'] = int(line.split(':')[1]) - 1 77dec49e00SJed Brown # Q 78d13e9b48SJed Brown elif 'Quadrature Points' in line: 79aa2aa0aeSJed Brown data['quadrature_pts'] = int(line.split(':')[1]) 80dec49e00SJed Brown # Total DOFs 81d13e9b48SJed Brown elif 'Global nodes' in line: 82d13e9b48SJed Brown data['num_unknowns'] = int(line.split(':')[1]) 83d13e9b48SJed Brown if data['case'] == 'vector': 84d13e9b48SJed Brown data['num_unknowns'] *= 3 85aa2aa0aeSJed Brown elif 'Global DOFs' in line: # Legacy 86aa2aa0aeSJed Brown data['num_unknowns'] = int(line.split(':')[1]) 87dec49e00SJed Brown # Number of elements 88d13e9b48SJed Brown elif 'Local Elements' in line: 89dec49e00SJed Brown data['num_elem'] = int( 90dec49e00SJed Brown line.split(':')[1].split()[0]) * data['num_procs'] 91aa2aa0aeSJed Brown elif 'DoF per node' in line: 92aa2aa0aeSJed Brown data['dof_per_node'] = int(line.split(':')[1]) 93dec49e00SJed Brown # CG Solve Time 94d13e9b48SJed Brown elif 'Total KSP Iterations' in line: 95d13e9b48SJed Brown data['ksp_its'] = int(line.split(':')[1].split()[0]) 96d13e9b48SJed Brown elif 'CG Solve Time' in line: 97dec49e00SJed Brown data['time_per_it'] = float( 98dec49e00SJed Brown line.split(':')[1].split()[0]) / data['ksp_its'] 99dec49e00SJed Brown # CG DOFs/Sec 100aa2aa0aeSJed Brown elif 'DoFs/Sec in CG' in line or 'DOFs/Sec in CG' in line: 101dec49e00SJed Brown data['cg_iteration_dps'] = 1e6 * \ 102dec49e00SJed Brown float(line.split(':')[1].split()[0]) 103dec49e00SJed Brown # End of output 104d13e9b48SJed Brown 105d13e9b48SJed Brown return pd.DataFrame(runs) 106d13e9b48SJed Brown 107dec49e00SJed Brown 108d13e9b48SJed Brownif __name__ == "__main__": 109d13e9b48SJed Brown runs = read_logs() 110aa2aa0aeSJed Brown print(runs) # Print summary (about 10 lines) 111aa2aa0aeSJed Brown print('First entry:\n', runs.iloc[0]) 112aa2aa0aeSJed Brown print('Last entry:\n', runs.iloc[-1]) 113