123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- import datetime as dt
- from paraview import servermanager
- from paraview.simple import *
- from paraview.benchmark import *
- #import logbase, logparser
- logbase.maximize_logs()
- records = []
- n0 = dt.datetime.now()
- def get_render_view(size):
- '''Similar to GetRenderView except if a new view is created, it's
- created with the specified size instead of having t resize afterwards
- '''
- view = active_objects.view
- if not view:
- # it's possible that there's no active view, but a render view exists.
- # If so, locate that and return it (before trying to create a new one).
- view = servermanager.GetRenderView()
- if not view:
- view = CreateRenderView(ViewSize=size)
- return view
- def save_render_buffer(fname):
- '''Similar to SaveScreenshot except a re-render will not be triggered'''
- from vtkmodules.vtkRenderingCore import vtkWindowToImageFilter
- w = GetRenderView().SMProxy.GetRenderWindow()
- w2i = vtkWindowToImageFilter()
- w2i.ReadFrontBufferOff()
- w2i.ShouldRerenderOff()
- w2i.SetInput(w)
- w2i.Modified()
- png = PNGWriter()
- png.Input = w2i.GetOutput()
- png.FileName = fname
- png.UpdatePipeline()
- def flush_render_buffer():
- '''When running as a single process use the WindowToImage filter to
- force a framebuffer read. This bypasses driver optimizations that
- perform lazy rendering and allows you to get actual frame rates for
- a single process with a GPU. Multi-process doesn't need this since
- compositing forces the frame buffer read.
- '''
- # If we're not using off-screen rendering then we can bypass this since
- # the frame buffer display will force a GL flush
- w = GetRenderView().SMProxy.GetRenderWindow()
- if not w.GetOffScreenRendering():
- return
- from vtkmodules.vtkRenderingCore import vtkWindowToImageFilter
- from vtkmodules.vtkParallelCore import vtkMultiProcessController
- # If we're using MPI we can also bypass this since compositing will
- # for a GL flush
- controller = vtkMultiProcessController.GetGlobalController()
- if controller.GetNumberOfProcesses() > 1:
- return
- # Force a GL flush by retrieving the frame buffer image
- w2i = vtkWindowToImageFilter()
- w2i.ReadFrontBufferOff()
- w2i.ShouldRerenderOff()
- w2i.SetInput(w)
- w2i.Modified()
- w2i.Update()
- def memtime_stamp():
- global records
- global n0
- m = logbase.get_memuse()
- n1 = dt.datetime.now()
- et = n1 - n0
- print(et, m)
- n0 = n1
- records.append([et, m])
- def run(output_basename='log', num_spheres=8, num_spheres_in_scene=None,
- resolution=725, view_size=(1920, 1080), num_frames=10, save_logs=True,
- transparency=False, ospray=False):
- if num_spheres_in_scene is None:
- num_spheres_in_scene = num_spheres
- from vtkmodules.vtkParallelCore import vtkMultiProcessController
- from vtkmodules.vtkCommonSystem import vtkTimerLog
- controller = vtkMultiProcessController.GetGlobalController()
- view = get_render_view(view_size)
- if ospray:
- view.EnableRayTracing = 1
- print('Generating bounding box')
- import math
- edge = math.ceil(math.pow(num_spheres_in_scene, (1.0 / 3.0)))
- box = Box()
- box.XLength = edge
- box.YLength = edge
- box.ZLength = edge
- box.Center = [edge * 0.5, edge * 0.5, edge * 0.5]
- boxDisplay = Show()
- boxDisplay.SetRepresentationType('Outline')
- print('Generating all spheres')
- gen = ProgrammableSource(Script='''
- import math
- from vtkmodules.vtkParallelCore import vtkMultiProcessController
- from vtkmodules.vtkFiltersSources import vtkSphereSource
- from vtkmodules.vtkFiltersCore import vtkAppendPolyData
- from vtkmodules.vtkCommonDataModel import vtkPolyData
- try:
- num_spheres
- except:
- num_spheres = 8
- try:
- num_spheres_in_scene
- except:
- num_spheres_in_scene = num_spheres
- try:
- res
- except:
- res = 725
- edge = math.ceil(math.pow(num_spheres_in_scene, (1.0 / 3.0)))
- controller = vtkMultiProcessController.GetGlobalController()
- np = controller.GetNumberOfProcesses()
- p = controller.GetLocalProcessId()
- ns=lambda rank:num_spheres/np + (1 if rank >= np-num_spheres%np else 0)
- # Not sure why but the builtin sum() gives weird results here so we'll just
- # so it manually
- start=0
- for r in range(0,p):
- start += int(ns(r))
- end=start+ns(p)
- start = int(start)
- end = int(end)
- ss = vtkSphereSource()
- ss.SetPhiResolution(res)
- ss.SetThetaResolution(res)
- ap = vtkAppendPolyData()
- print(' source %d: generating %d spheres from %d to %d' % (p, end-start, start, end))
- for x in range(start,end):
- i = x%edge
- j = math.floor((x / edge))%edge
- k = math.floor((x / (edge * edge)))
- ss.SetCenter(i + 0.5,j + 0.5,k + 0.5)
- ss.Update()
- pd = vtkPolyData()
- pd.ShallowCopy(ss.GetOutput())
- # pd.GetPointData().RemoveArray('Normals')
- ap.AddInputData(pd)
- ap.Update()
- self.GetOutput().ShallowCopy(ap.GetOutput())
- ''')
- paramprop = gen.GetProperty('Parameters')
- paramprop.SetElement(0, 'num_spheres_in_scene')
- paramprop.SetElement(1, str(num_spheres_in_scene))
- paramprop.SetElement(2, 'num_spheres')
- paramprop.SetElement(3, str(num_spheres))
- paramprop.SetElement(4, 'res')
- paramprop.SetElement(5, str(resolution))
- gen.UpdateProperty('Parameters')
- print('Assigning colors')
- pidScale = ProcessIdScalars()
- pidScaleDisplay = Show()
- pidScaleDisplay.SetRepresentationType('Surface')
- if transparency:
- print('Enabling 50% transparency')
- pidScaleDisplay.Opacity = 0.5
- print('Repositioning initial camera')
- c = GetActiveCamera()
- c.Azimuth(22.5)
- c.Elevation(22.5)
- print('Rendering first frame')
- Render()
- print('Saving frame 0 screenshot')
- fdigits = int(math.ceil(math.log(num_frames, 10)))
- frame_fname_fmt = output_basename + '.scene.f%(f)0' + str(fdigits) + 'd.png'
- SaveScreenshot(frame_fname_fmt % {'f': 0})
- print('Gathering geometry counts')
- vtkTimerLog.MarkStartEvent('GetViewItemStats')
- num_polys = 0
- num_points = 0
- for r in view.Representations:
- num_polys += r.GetRepresentedDataInformation().GetNumberOfCells()
- num_points += r.GetRepresentedDataInformation().GetNumberOfPoints()
- vtkTimerLog.MarkEndEvent('GetViewItemStats')
- print('Beginning benchmark loop')
- deltaAz = 45.0 / num_frames
- deltaEl = 45.0 / num_frames
- memtime_stamp()
- fpsT0 = dt.datetime.now()
- for frame in range(1, num_frames):
- c.Azimuth(deltaAz)
- c.Elevation(deltaEl)
- Render()
- flush_render_buffer()
- memtime_stamp()
- fpsT1 = dt.datetime.now()
- if controller.GetLocalProcessId() == 0:
- if save_logs:
- # Save the arguments this was executed with
- with open(output_basename + '.args.txt', 'w') as argfile:
- argfile.write(str({
- 'output_basename': output_basename,
- 'num_spheres': num_spheres,
- 'num_spheres_in_scene': num_spheres_in_scene,
- 'resolution': resolution, 'view_size': view_size,
- 'num_frames': num_frames, 'save_logs': save_logs,
- 'transparency': transparency, 'ospray': ospray}))
- # Save the memory statistics collected
- with open(output_basename + '.mem.txt', 'w') as ofile:
- ofile.write('\n'.join([str(x) for x in records]))
- # Process frame timing statistics
- logparser.summarize_results(num_frames, (fpsT1-fpsT0).total_seconds(),
- num_polys, 'Polys', save_logs,
- output_basename)
- print('Points / Frame: %d' % (num_points))
- def main(argv):
- import argparse
- parser = argparse.ArgumentParser(
- description='Benchmark ParaView geometry rendering')
- parser.add_argument('-o', '--output-basename', default='log', type=str,
- help='Basename to use for generated output files')
- parser.add_argument('-s', '--spheres', default=100, type=int,
- help='The total number of spheres to render')
- parser.add_argument('-n', '--spheres-in-scene', type=int,
- help='The number of spheres in the entire scene, including those not rendered.')
- parser.add_argument('-r', '--resolution', default=4, type=int,
- help='Theta and Phi resolution to use for the spheres')
- parser.add_argument('-v', '--view-size', default=[400, 400],
- type=lambda s: [int(x) for x in s.split(',')],
- help='View size used to render')
- parser.add_argument('-f', '--frames', default=10, type=int,
- help='Number of frames')
- parser.add_argument('-t', '--transparency', action='store_true',
- help='Enable transparency')
- parser.add_argument('-y', '--ospray', action='store_true',
- help='Use OSPRAY to render')
- args = parser.parse_args(argv)
- options = servermanager.vtkRemotingCoreConfiguration.GetInstance()
- url = options.GetServerURL()
- if url:
- import re
- m = re.match('([^:/]*://)?([^:]*)(:([0-9]+))?', url)
- if m.group(4):
- Connect(m.group(2), m.group(4))
- else:
- Connect(m.group(2))
- run(output_basename=args.output_basename, num_spheres=args.spheres,
- num_spheres_in_scene=args.spheres_in_scene, resolution=args.resolution,
- view_size=args.view_size, num_frames=args.frames,
- transparency=args.transparency, ospray=args.ospray)
- if __name__ == "__main__":
- import sys
- main(sys.argv[1:])
|