vtk-m/vtkm/internal/FunctionInterfaceDetailPre.h.in
Robert Maynard c1560e2d3f Perform less unnecessary copies when deducing a worklets parameters.
One of the causes of the large library size and slow compile times has been
that vtkm has been creating unnecessary copies when not needed. When the
objects being copied use shared_ptr this causes a bloom in library size. I
presume this bloom is caused by the atomic increment/decrement that is
required by shared_ptr.

For testing I used the following example:
```
struct ExampleFieldWorklet : public vtkm::worklet::WorkletMapField
{
  typedef void ControlSignature( FieldIn<>, FieldIn<>, FieldIn<>,
                                 FieldOut<>, FieldOut<>, FieldOut<> );
  typedef void ExecutionSignature( _1, _2, _3, _4, _5, _6 );

  template<typename T, typename U, typename V>
  VTKM_EXEC_EXPORT
  void operator()( const vtkm::Vec< T, 3 > & vec,
                   const U & scalar1,
                   const V& scalar2,
                   vtkm::Vec<T, 3>& out_vec,
                   U& out_scalar1,
                   V& out_scalar2 ) const
  {
    out_vec = vec * scalar1;
    out_scalar1 = scalar1 + scalar2;
    out_scalar2 = scalar2;
  }

  template<typename T, typename U, typename V, typename W, typename X, typename Y>
  VTKM_EXEC_EXPORT
  void operator()( const T & vec,
                   const U & scalar1,
                   const V& scalar2,
                   W& out_vec,
                   X& out_scalar,
                   Y& ) const
  {
  //no-op
  }
};

int main(int argc, char** argv)
{
  std::vector< vtkm::Vec<vtkm::Float32, 3> > inputVec;
  std::vector< vtkm::Int32 > inputScalar1;
  std::vector< vtkm::Float64 > inputScalar2;

  vtkm::cont::ArrayHandle< vtkm::Vec<vtkm::Float32, 3> > handleV =
    vtkm::cont::make_ArrayHandle(inputVec);

  vtkm::cont::ArrayHandle< vtkm::Vec<vtkm::Float32, 3> > handleS1 =
    vtkm::cont::make_ArrayHandle(inputVec);

  vtkm::cont::ArrayHandle< vtkm::Vec<vtkm::Float32, 3> > handleS2 =
    vtkm::cont::make_ArrayHandle(inputVec);

  vtkm::cont::ArrayHandle< vtkm::Vec<vtkm::Float32, 3> > handleOV;
  vtkm::cont::ArrayHandle< vtkm::Vec<vtkm::Float32, 3> > handleOS1;
  vtkm::cont::ArrayHandle< vtkm::Vec<vtkm::Float32, 3> > handleOS2;

  std::cout << "Making 3 output DynamicArrayHandles " << std::endl;
  vtkm::cont::DynamicArrayHandle out1(handleOV), out2(handleOS1), out3(handleOS2);

  typedef vtkm::worklet::DispatcherMapField<ExampleFieldWorklet> DispatcherType;

  std::cout << "Invoking ExampleFieldWorklet" << std::endl;
  DispatcherType dispatcher;

  dispatcher.Invoke(handleV, handleS1, handleS2, out1, out2, out3);

}
```

Original vtkm would generate a binary of size 4684kb and would perform 91
ArrayHandle copies or assignments. With this branch the binary size is
reduced to 2392kb and will perform 36 copies or assignments.
2016-01-19 09:20:49 -05:00

283 lines
8.7 KiB
C

//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
$# This file uses the pyexpander macro processing utility to build the
$# FunctionInterface facilities that use a variable number of arguments.
$# Information, documentation, and downloads for pyexpander can be found at:
$#
$# http://pyexpander.sourceforge.net/
$#
$# To build the source code, execute the following (after installing
$# pyexpander, of course):
$#
$# expander.py FunctionInterfaceDetailPre.h.in > FunctionInterfaceDetailPre.h
$#
$# Ignore the following comment. It is meant for the generated file.
// **** DO NOT EDIT THIS FILE!!! ****
// This file is automatically generated by FunctionInterfaceDetailPre.h.in
#ifndef vtk_m_internal_FunctionInterfaceDetailPre_h
#define vtk_m_internal_FunctionInterfaceDetailPre_h
#if !defined(vtk_m_internal_FunctionInterface_h) && !defined(VTKM_TEST_HEADER_BUILD)
#error FunctionInterfaceDetailPre.h must be included from FunctionInterface.h
#endif
#include <vtkm/Types.h>
#include <vtkm/internal/IndexTag.h>
VTKM_THIRDPARTY_PRE_INCLUDE
#include <boost/function_types/function_type.hpp>
#include <boost/mpl/at.hpp>
VTKM_THIRDPARTY_POST_INCLUDE
$py(max_parameters=10)\
#define VTKM_MAX_FUNCTION_PARAMETERS $(max_parameters)
$# Python commands used in template expansion.
$py(
def comma_if(flag):
if flag:
return ','
else:
return '';
def ptype(num, name=""):
if num == 0:
return '%sR' % name
else:
return '%sP%d' % (name, num)
def template_params(num_params, start=0, name=''):
if num_params < start:
return ''
result = 'typename %s' % ptype(start, name)
for param in xrange(start+1, num_params+1):
result += ',\n typename %s' % ptype(param, name)
return result
def signature(num_params, return_type=ptype(0), name=''):
result = '%s(' % return_type
if num_params > 0:
result += ptype(1, name)
for param in xrange(2, num_params+1):
result += ',%s' % ptype(param, name)
result += ')'
return result
)\
$#
$extend(comma_if, ptype, template_params, signature)\
namespace vtkm {
namespace internal {
/// This struct is used internally by FunctionInterface to store the return
/// value of a function. There is a special implementation for a return type of
/// void, which stores nothing.
///
template<typename T>
struct FunctionInterfaceReturnContainer {
T Value;
static const bool VALID = true;
};
template<>
struct FunctionInterfaceReturnContainer<void> {
// Nothing to store for void return.
static const bool VALID = false;
};
namespace detail {
//============================================================================
// This templated class contains the state of parameters. If you get a compiler
// error stating that this class is not specialized, that probably means that
// you are using FunctionInterface with an unsupported number of arguments.
template<typename FunctionSignature>
struct ParameterContainer;
$for(num_params in range(0, max_parameters+1))\
template<$template_params(num_params)>
struct ParameterContainer<$signature(num_params)> {
$for(param_index in range(1, num_params+1))\
$ptype(param_index) Parameter$(param_index);
$endfor\
};
$endfor\
//============================================================================
template<int ParameterIndex, typename FunctionSignature>
struct ParameterContainerAccess;
$for(param_index in range(1, max_parameters+1))\
template<typename FunctionSignature>
struct ParameterContainerAccess<$(param_index), FunctionSignature> {
typedef typename boost::mpl::at_c<
boost::function_types::components<FunctionSignature>, $(param_index)>::type
ParameterType;
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT_EXPORT
static
const ParameterType&
GetParameter(const ParameterContainer<FunctionSignature> &parameters) {
return parameters.Parameter$(param_index);
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT_EXPORT
static
void SetParameter(ParameterContainer<FunctionSignature> &parameters,
const ParameterType &value) {
parameters.Parameter$(param_index) = value;
}
};
$endfor\
//============================================================================
$for(num_params in range(0, max_parameters+1))\
$# Invoke functions need both control and execution versions
$for(environment in ['Cont', 'Exec'])\
$# Invoke functions also need to accept const and non-const versions of the functor
$for(functor_const in ['const ', ''])\
VTKM_SUPPRESS_EXEC_WARNINGS
template<typename Functor,
typename TransformFunctor,
$template_params(num_params)>
VTKM_$(environment.upper())_EXPORT
void DoInvoke$(environment)(
$(functor_const)Functor &f,
ParameterContainer<$signature(num_params)> &parameters,
FunctionInterfaceReturnContainer<$ptype(0)> &result,
const TransformFunctor &transform)
{
$if(num_params < 1)\
(void) parameters;
result.Value = transform(f());
$else\
result.Value = transform(f(
$for(param_index in xrange(1, num_params))\
transform(parameters.Parameter$(param_index)),
$endfor\
transform(parameters.Parameter$(num_params))));
$endif\
}
VTKM_SUPPRESS_EXEC_WARNINGS
template<typename Functor,
typename TransformFunctor$comma_if(num_params>0)
$template_params(num_params,1)>
VTKM_$(environment.upper())_EXPORT
void DoInvoke$(environment)(
$(functor_const)Functor &f,
ParameterContainer<$signature(num_params,'void')> &parameters,
FunctionInterfaceReturnContainer<void> &,
const TransformFunctor &transform)
{
$if(num_params < 1)\
(void) parameters;
(void) transform;
f();
$else\
f(
$for(param_index in xrange(1, num_params))\
transform(parameters.Parameter$(param_index)),
$endfor\
transform(parameters.Parameter$(num_params)));
$endif\
}
$endfor\
$endfor\
$endfor\
//============================================================================
template<typename OriginalSignature, typename Transform>
struct FunctionInterfaceStaticTransformType;
$for(num_params in xrange(0, max_parameters))\
$# Transform functions need both control and execution versions
$for(environment in ['Cont', 'Exec'])\
VTKM_SUPPRESS_EXEC_WARNINGS
template<typename Transform,
$template_params(num_params,0,'Original'),
$template_params(num_params,0,'Transformed')>
VTKM_$(environment.upper())_EXPORT
void DoStaticTransform$(environment)(
const Transform &transform,
const ParameterContainer<$signature(num_params,ptype(0,'Original'),'Original')> &originalParameters,
ParameterContainer<$signature(num_params,ptype(0,'Transformed'),'Transformed')> &transformedParameters)
{
$if(num_params < 1)\
(void)transform;
(void)originalParameters;
(void)transformedParameters;
$else\
$for(param_index in xrange(1, num_params+1))\
transformedParameters.Parameter$(param_index) =
transform(originalParameters.Parameter$(param_index), vtkm::internal::IndexTag<$(param_index)>());
$endfor\
$endif\
}
$endfor\
$endfor\
//============================================================================
$for(num_params in xrange(0, max_parameters))\
$# ForEach functions need both control and execution versions
$for(environment in ['Cont', 'Exec'])\
$# ForEach functions also need to accept const and non-const versions of the FunctionInterface
$for(function_interface_const in ['const ', ''])\
VTKM_SUPPRESS_EXEC_WARNINGS
template<typename Functor,
$template_params(num_params)>
VTKM_$(environment.upper())_EXPORT
void DoForEach$(environment)(
const Functor &f,
$(function_interface_const)ParameterContainer<$signature(num_params)> &parameters)
{
$if(num_params < 1)\
(void)f;
(void)parameters;
$else\
$for(param_index in xrange(1, num_params+1))\
f(parameters.Parameter$(param_index), vtkm::internal::IndexTag<$(param_index)>());
$endfor\
$endif\
}
$endfor\
$endfor\
$endfor\
} // namespace detail
}
} // namespace vtkm::internal
#endif //vtk_m_internal_FunctionInterfaceDetailPre_h