xref: /petsc/src/benchmarks/benchmarkAssembly.py (revision d5b43468fb8780a8feea140ccd6fa3e6a50411cc)
1#!/usr/bin/env python
2from __future__ import print_function
3import os
4from benchmarkExample import PETScExample
5
6savedTiming = {'baconost': {'ElemAssembly': [(0.040919999999999998, 0.0), (0.1242, 0.0), (0.24410000000000001, 0.0), (0.374, 0.0), (0.56259999999999999, 0.0), (0.79049999999999998, 0.0), (1.0880000000000001, 0.0), (1.351, 0.0), (1.6930000000000001, 0.0), (2.0609999999999999, 0.0), (2.4820000000000002, 0.0), (3.0640000000000001, 0.0)],
7                            'MatCUSPSetValBch': [(0.0123, 0.0), (0.023429999999999999, 0.0), (0.043540000000000002, 0.0), (0.06608, 0.0), (0.09579, 0.0), (0.12920000000000001, 0.0), (0.17169999999999999, 0.0), (0.2172, 0.0), (0.27179999999999999, 0.0), (0.48309999999999997, 0.0), (0.44180000000000003, 0.0), (0.51529999999999998, 0.0)]}
8               }
9
10def calculateNonzeros(n):
11  num = 0
12  # corners
13  num += 2*3 + 2*4
14  # edges
15  num += 4*(n-2)*5
16  # interior
17  num += (n-2)*(n-2)*7
18  return num
19
20def processSummary(moduleName, times, events):
21  '''Process the Python log summary into plot data'''
22  m = __import__(moduleName)
23  reload(m)
24  # Total Time
25  times.append(m.Time[0])
26  # Common events
27  #   Add the time and flop rate
28  for stageName, eventName in [('GPU_Stage','MatCUSPSetValBch'), ('CPU_Stage','ElemAssembly')]:
29    s = getattr(m, stageName)
30    if not eventName in events:
31      events[eventName] = []
32    events[eventName].append((s.event[eventName].Time[0], s.event[eventName].Flops[0]/(s.event[eventName].Time[0] * 1e6)))
33  return
34
35def plotSummary(library, num, sizes, nonzeros, times, events):
36  from pylab import legend, plot, show, title, xlabel, ylabel, ylim
37  import numpy as np
38  showEventTime      = True
39  showTimePerRow     = False
40  showTimePerNonzero = True
41  print(events)
42  if showEventTime:
43    data  = []
44    names = []
45    for event, style in [('MatCUSPSetValBch', 'b-'), ('ElemAssembly', 'b:')]:
46      names.append(event)
47      data.append(sizes)
48      data.append(np.array(events[event])[:,0])
49      data.append(style)
50    plot(*data)
51    title('Performance on '+library+' Example '+str(num))
52    xlabel('Number of Dof')
53    ylabel('Time (s)')
54    legend(names, 'upper left', shadow = True)
55    show()
56  if showTimePerRow:
57    data  = []
58    names = []
59    for event, style in [('MatCUSPSetValBch', 'b-'), ('ElemAssembly', 'b:')]:
60      names.append(event)
61      data.append(sizes)
62      rows = np.sqrt(sizes)
63      data.append(np.array(events[event])[:,0]/rows/3)
64      data.append(style)
65    plot(*data)
66    title('Performance on '+library+' Example '+str(num))
67    xlabel('Number of Dof')
68    ylabel('Time/Row (s)')
69    legend(names, 'upper left', shadow = True)
70    show()
71  if showTimePerNonzero:
72    data  = []
73    names = []
74    for event, style in [('MatCUSPSetValBch', 'b-'), ('ElemAssembly', 'b:')]:
75      names.append(event)
76      data.append(sizes)
77      data.append(np.array(events[event])[:,0]/nonzeros * 10**9)
78      data.append(style)
79    plot(*data)
80    title('Performance on '+library+' Example '+str(num))
81    xlabel('Number of Dof')
82    ylabel('Time/Nonzero (ns)')
83    legend(names, 'center right', shadow = True)
84    show()
85  return
86
87if __name__ == '__main__':
88  import argparse
89
90  parser = argparse.ArgumentParser(description     = 'PETSc Benchmarking',
91                                   epilog          = 'This script runs src/<library>/tutorials/ex<num>, For more information, visit https://petsc.org/',
92                                   formatter_class = argparse.ArgumentDefaultsHelpFormatter)
93  parser.add_argument('--library', default='SNES',          help='The PETSc library used in this example')
94  parser.add_argument('--num',     type = int, default='5', help='The example number')
95  parser.add_argument('--module',  default='summary',       help='The module for timing output')
96  parser.add_argument('--saved',                            help='Name of saved data')
97  parser.add_argument('--scaling',                          help='Run parallel scaling test')
98  parser.add_argument('--small',   action='store_true', default=False, help='Use small sizes')
99  parser.add_argument('--batch',   action='store_true', default=False, help='Generate batch files for the runs instead')
100
101  args = parser.parse_args()
102  print(args)
103  ex       = PETScExample(args.library, args.num, log_summary_python = None if args.batch else args.module+'.py', preload='off')
104  sizes    = []
105  nonzeros = []
106  times    = []
107  if args.saved is None:
108    events   = {}
109    if args.scaling == 'strong':
110      procs  = [1, 2, 4, 8]
111      if args.small:
112        grid = [10]*len(procs)
113      else:
114        grid = [1250]*len(procs)
115    else:
116      if args.small:
117        grid = [100, 150, 200, 250, 300]
118      else:
119        grid = range(150, 1350, 100)
120      procs  = [1]*len(grid)
121    for n, p in zip(grid, procs):
122      ex.run(p, da_grid_x=n, da_grid_y=n, cusp_synchronize=1, batch=args.batch)
123      sizes.append(n*n)
124      nonzeros.append(calculateNonzeros(n))
125      if not args.batch:
126        processSummary(args.module, times, events)
127        os.remove(args.module+'.pyc')
128  else:
129    if args.batch: raise RuntimeException('Cannot use batch option with saved data')
130    if args.saved in savedTiming:
131      events = savedTiming[args.saved]
132    else:
133      # Process output to produce module
134      events       = {}
135      filenameBase = args.saved[:-7]
136      jobnumBase   = int(args.saved[-7:])
137      for i, n in enumerate(range(150, 1350, 100)):
138        filename = filenameBase+str(jobnumBase+i)
139        print('Processing',filename)
140        headerSeen = False
141        with file(filename) as f, file(args.module+'.py', 'w') as o:
142          for line in f.readlines():
143            if not headerSeen:
144              if not line[0] == '#': continue
145              headerSeen = True
146            if line[0] == '#' and line[-6:] == '=====\n': break
147            o.write(line)
148            #print line
149        processSummary(args.module, times, events)
150        # I can't believe that this is necessary
151        os.remove(args.module+'.pyc')
152    for n in range(150, 1350, 100):
153      sizes.append(n*n)
154      nonzeros.append(calculateNonzeros(n))
155  if not args.batch: plotSummary(args.library, args.num, sizes, nonzeros, times, events)
156