Commit 53a454fe authored by Kenneth Moreland's avatar Kenneth Moreland

Add basic dispatcher functionality.

These changes support the implementation of DispatcherBase. This class
provides the basic functionality for calling an Invoke method in the
control environment, transferring data to the execution environment,
scheduling threads in the execution environment, pulling data for each
calling of the worklet method, and actually calling the worklet.
parent b78688f4
......@@ -83,7 +83,9 @@ struct FetchArrayDirectInTests
this->TryInvocation(vtkm::internal::make_Invocation<1>(
BaseFunctionInterface().Replace<ParamIndex>(
TestPortal<T>())));
TestPortal<T>()),
NullParam(),
NullParam()));
}
};
......
......@@ -94,7 +94,9 @@ struct FetchArrayDirectOutTests
this->TryInvocation(vtkm::internal::make_Invocation<1>(
BaseFunctionInterface().Replace<ParamIndex>(
TestPortal<T>())));
TestPortal<T>()),
NullParam(),
NullParam()));
}
};
......
......@@ -78,7 +78,9 @@ void TryParamIndex()
TryInvocation<ParamIndex>(vtkm::internal::make_Invocation<1>(
BaseFunctionInterface().Replace<ParamIndex>(
TestExecutionObject(EXPECTED_NUMBER))));
TestExecutionObject(EXPECTED_NUMBER)),
NullParam(),
NullParam()));
}
void TestExecObjectFetch()
......
......@@ -63,7 +63,9 @@ void TestWorkIndexFetch()
void(NullParam,NullParam,NullParam,NullParam,NullParam)>
BaseFunctionInterface;
TryInvocation(vtkm::internal::make_Invocation<1>( BaseFunctionInterface()));
TryInvocation(vtkm::internal::make_Invocation<1>(BaseFunctionInterface(),
NullParam(),
NullParam()));
}
} // anonymous namespace
......
......@@ -20,8 +20,12 @@
set(headers
ErrorMessageBuffer.h
WorkletInvokeFunctor.h
WorkletInvokeFunctorDetail.h
)
vtkm_declare_headers(${headers})
vtkm_pyexpander_generated_file(WorkletInvokeFunctorDetail.h)
add_subdirectory(testing)
//============================================================================
// 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.
//============================================================================
#ifndef vtk_m_exec_internal_WorkletInvokeFunctor_h
#define vtk_m_exec_internal_WorkletInvokeFunctor_h
#include <vtkm/internal/Invocation.h>
#include <vtkm/exec/FunctorBase.h>
#include <vtkm/exec/arg/Fetch.h>
#include <vtkm/exec/internal/WorkletInvokeFunctorDetail.h>
namespace vtkm {
namespace exec {
namespace internal {
template<typename WorkletType, typename InvocationType>
class WorkletInvokeFunctor : public vtkm::exec::FunctorBase
{
public:
VTKM_CONT_EXPORT
WorkletInvokeFunctor(const WorkletType &worklet,
const InvocationType &invocation)
: Worklet(worklet), Invocation(invocation) { }
VTKM_CONT_EXPORT
void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &buffer)
{
this->FunctorBase::SetErrorMessageBuffer(buffer);
this->Worklet.SetErrorMessageBuffer(buffer);
}
VTKM_EXEC_EXPORT
void operator()(vtkm::Id index) const
{
detail::DoWorkletInvokeFunctor(this->Worklet, this->Invocation, index);
}
private:
WorkletType Worklet;
InvocationType Invocation;
};
}
}
} // vtkm::exec::internal
#endif //vtk_m_exec_internal_WorkletInvokeFunctor_h
This diff is collapsed.
//============================================================================
// 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 WorkletInvokeFunctorDetail.h.in > WorkletInvokeFunctorDetail.h
$#
$# Ignore the following comment. It is meant for the generated file.
// **** DO NOT EDIT THIS FILE!!! ****
// This file is automatically generated by WorkletInvokeFunctorDetail.h.in
// Technically speaking, we can implement this functionality with some clever
// use of FunctionInterface rather than using pyexpander to make variadic
// code. However, this code is probably more friendly to compilers. I expect
// it to compiler faster and optimize better.
#ifndef vtk_m_exec_internal_WorkletInvokeFunctorDetail_h
#define vtk_m_exec_internal_WorkletInvokeFunctorDetail_h
#if !defined(vtk_m_exec_internal_WorkletInvokeFunctor_h) && !defined(VTKM_TEST_HEADER_BUILD)
#error WorkletInvokeFunctorDetail.h must be included from WorkletInvokeFunctor.h
#endif
#include <vtkm/internal/FunctionInterface.h>
#include <vtkm/internal/Invocation.h>
#include <vtkm/exec/arg/Fetch.h>
$# This needs to match the max_parameters in FunctionInterfaceDetailPre.h.in
$py(max_parameters=10)\
#if VTKM_MAX_FUNCTION_PARAMETERS != $(max_parameters)
#error Mismatch of maximum parameters between FunctionInterfaceDatailPre.h.in and WorkletInvokeFunctorDetail.h.in
#endif
$# 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 pname(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
def arg_list(num_params, name='', start=1):
if num_params < start:
return ''
result = pname(start, name)
for param in xrange(start+1, num_params+1):
result += ',%s' % pname(param, name)
return result
)\
$#
$extend(comma_if, ptype, pname, template_params, signature, arg_list)\
namespace vtkm {
namespace exec {
namespace internal {
namespace detail {
/// A helper class that takes an \c Invocation object and an index to a
/// parameter in the ExecutionSignature and finds the \c Fetch type valid for
/// that parameter.
template<typename Invocation, vtkm::IdComponent ExecutionParameterIndex>
struct InvocationToFetch
{
private:
typedef typename Invocation::ExecutionInterface::
template ParameterType<ExecutionParameterIndex>::type
ExecutionSignatureTag;
// Expected fields from ExecutionSignatureTag. If these do not exist in
// ExecutionSignatureTag, then something that is not really an execution
// signature tag was used in an ExecutionSignature.
static const vtkm::IdComponent ControlParameterIndex =
ExecutionSignatureTag::INDEX;
typedef typename ExecutionSignatureTag::AspectTag AspectTag;
// Find the fetch tag from the control signature tag pointed to by
// ParameterIndex.
typedef typename Invocation::ControlInterface ControlInterface;
typedef typename ControlInterface::
template ParameterType<ControlParameterIndex>::type ControlSignatureTag;
typedef typename ControlSignatureTag::FetchTag FetchTag;
public:
typedef vtkm::exec::arg::Fetch<
FetchTag,AspectTag,Invocation,ControlParameterIndex> type;
};
$for(num_params in range(1, max_parameters+1))\
template<typename WorkletType,
typename ParameterInterface,
typename ControlInterface,
vtkm::IdComponent InputDomainIndex,
$template_params(num_params)>
void DoWorkletInvokeFunctor(
const WorkletType &worklet,
const vtkm::internal::Invocation<
ParameterInterface,
ControlInterface,
vtkm::internal::FunctionInterface<$signature(num_params)>,
InputDomainIndex> &invocation,
vtkm::Id index)
{
typedef vtkm::internal::Invocation<
ParameterInterface,
ControlInterface,
vtkm::internal::FunctionInterface<$signature(num_params)>,
InputDomainIndex> Invocation;
$for(param_index in range(1, num_params+1))\
typedef typename InvocationToFetch<Invocation,$(param_index)>::type FetchType$(param_index);
FetchType$(param_index) fetch$(param_index);
typename FetchType$(param_index)::ValueType $pname(param_index) = fetch$(param_index).Load(index, invocation);
$endfor\
typedef typename InvocationToFetch<Invocation,0>::type ReturnFetchType;
ReturnFetchType returnFetch;
typename ReturnFetchType::ValueType $pname(0) = worklet($arg_list(num_params));
returnFetch.Store(index, invocation, $pname(0));
$for(param_index in range(1, num_params+1))\
fetch$(param_index).Store(index, invocation, $pname(param_index));
$endfor\
}
template<typename WorkletType,
typename ParameterInterface,
typename ControlInterface,
vtkm::IdComponent InputDomainIndex,
$template_params(num_params, start=1)>
void DoWorkletInvokeFunctor(
const WorkletType &worklet,
const vtkm::internal::Invocation<
ParameterInterface,
ControlInterface,
vtkm::internal::FunctionInterface<$signature(num_params, return_type='void')>,
InputDomainIndex> &invocation,
vtkm::Id index)
{
typedef vtkm::internal::Invocation<
ParameterInterface,
ControlInterface,
vtkm::internal::FunctionInterface<$signature(num_params, return_type='void')>,
InputDomainIndex> Invocation;
$for(param_index in range(1, num_params+1))\
typedef typename InvocationToFetch<Invocation,$(param_index)>::type FetchType$(param_index);
FetchType$(param_index) fetch$(param_index);
typename FetchType$(param_index)::ValueType $pname(param_index) = fetch$(param_index).Load(index, invocation);
$endfor\
worklet($arg_list(num_params));
$for(param_index in range(1, num_params+1))\
fetch$(param_index).Store(index, invocation, $pname(param_index));
$endfor\
}
$endfor\
}
}
}
} // namespace vtkm::exec::internal::detail
#endif //vtk_m_exec_internal_WorkletInvokeFunctorDetail_h
......@@ -22,5 +22,6 @@
set(unit_tests
UnitTestErrorMessageBuffer.cxx
UnitTestWorkletInvokeFunctor.cxx
)
vtkm_unit_tests(SOURCES ${unit_tests})
//============================================================================
// 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.
//============================================================================
#include <vtkm/exec/internal/WorkletInvokeFunctor.h>
#include <vtkm/exec/arg/BasicArg.h>
#include <vtkm/internal/FunctionInterface.h>
#include <vtkm/testing/Testing.h>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
namespace {
struct TestExecObject
{
VTKM_EXEC_CONT_EXPORT
TestExecObject() : Value(NULL) { }
VTKM_EXEC_CONT_EXPORT
TestExecObject(vtkm::Id *value) : Value(value) { }
vtkm::Id *Value;
};
struct TestFetchTagInput { };
struct TestFetchTagOutput { };
// Missing TransportTag, but we are not testing that so we can leave it out.
struct TestControlSignatureTagInput
{
typedef TestFetchTagInput FetchTag;
};
struct TestControlSignatureTagOutput
{
typedef TestFetchTagOutput FetchTag;
};
} // anonymous namespace
namespace vtkm {
namespace exec {
namespace arg {
template<typename Invocation, vtkm::IdComponent ParameterIndex>
struct Fetch<TestFetchTagInput, vtkm::exec::arg::AspectTagDefault, Invocation, ParameterIndex>
{
typedef vtkm::Id ValueType;
VTKM_EXEC_EXPORT
ValueType Load(vtkm::Id index, const Invocation &invocation) const {
return *invocation.Parameters.
template GetParameter<ParameterIndex>().Value + 10*index;
}
VTKM_EXEC_EXPORT
void Store(vtkm::Id, const Invocation &, ValueType) const {
// No-op
}
};
template<typename Invocation, vtkm::IdComponent ParameterIndex>
struct Fetch<TestFetchTagOutput, vtkm::exec::arg::AspectTagDefault, Invocation, ParameterIndex>
{
typedef vtkm::Id ValueType;
VTKM_EXEC_EXPORT
ValueType Load(vtkm::Id, const Invocation &) const {
// No-op
return ValueType();
}
VTKM_EXEC_EXPORT
void Store(vtkm::Id index,
const Invocation &invocation,
ValueType value) const {
*invocation.Parameters.template GetParameter<ParameterIndex>().Value =
value + 20*index;
}
};
}
}
} // vtkm::exec::arg
namespace {
typedef void TestControlSignature(TestControlSignatureTagInput,
TestControlSignatureTagOutput);
typedef vtkm::internal::FunctionInterface<TestControlSignature>
TestControlInterface;
typedef void TestExecutionSignature1(vtkm::exec::arg::BasicArg<1>,
vtkm::exec::arg::BasicArg<2>);
typedef vtkm::internal::FunctionInterface<TestExecutionSignature1>
TestExecutionInterface1;
typedef vtkm::exec::arg::BasicArg<2> TestExecutionSignature2(
vtkm::exec::arg::BasicArg<1>);
typedef vtkm::internal::FunctionInterface<TestExecutionSignature2>
TestExecutionInterface2;
typedef vtkm::internal::FunctionInterface<void(TestExecObject, TestExecObject)>
ExecutionParameterInterface;
typedef vtkm::internal::Invocation<
ExecutionParameterInterface,
TestControlInterface,
TestExecutionInterface1,
1> InvocationType1;
typedef vtkm::internal::Invocation<
ExecutionParameterInterface,
TestControlInterface,
TestExecutionInterface2,
1> InvocationType2;
// Not a full worklet, but provides operators that we expect in a worklet.
struct TestWorkletProxy : vtkm::exec::FunctorBase
{
VTKM_EXEC_EXPORT
void operator()(vtkm::Id input, vtkm::Id &output) const
{
output = input + 100;
}
VTKM_EXEC_EXPORT
vtkm::Id operator()(vtkm::Id input) const
{
return input + 200;
}
};
#define ERROR_MESSAGE "Expected worklet error."
// Not a full worklet, but provides operators that we expect in a worklet.
struct TestWorkletErrorProxy : vtkm::exec::FunctorBase
{
VTKM_EXEC_EXPORT
void operator()(vtkm::Id, vtkm::Id) const
{
this->RaiseError(ERROR_MESSAGE);
}
};
// Check behavior of InvocationToFetch helper class.
BOOST_MPL_ASSERT(( boost::is_same<
vtkm::exec::internal::detail::InvocationToFetch<InvocationType1,1>::type,
vtkm::exec::arg::Fetch<TestFetchTagInput,vtkm::exec::arg::AspectTagDefault,InvocationType1,1> > ));
BOOST_MPL_ASSERT(( boost::is_same<
vtkm::exec::internal::detail::InvocationToFetch<InvocationType1,2>::type,
vtkm::exec::arg::Fetch<TestFetchTagOutput,vtkm::exec::arg::AspectTagDefault,InvocationType1,2> > ));
BOOST_MPL_ASSERT(( boost::is_same<
vtkm::exec::internal::detail::InvocationToFetch<InvocationType2,0>::type,
vtkm::exec::arg::Fetch<TestFetchTagOutput,vtkm::exec::arg::AspectTagDefault,InvocationType2,2> > ));
void TestDoWorkletInvoke()
{
std::cout << "Testing internal worklet invoke." << std::endl;
vtkm::Id inputTestValue;
vtkm::Id outputTestValue;
vtkm::internal::FunctionInterface<void(TestExecObject,TestExecObject)> execObjects =
vtkm::internal::make_FunctionInterface<void>(TestExecObject(&inputTestValue),
TestExecObject(&outputTestValue));
std::cout << " Try void return." << std::endl;
inputTestValue = 5;
outputTestValue = 0xDEADDEAD;
vtkm::exec::internal::detail::DoWorkletInvokeFunctor(
TestWorkletProxy(),
vtkm::internal::make_Invocation<1>(execObjects,
TestControlInterface(),
TestExecutionInterface1()),
1);
VTKM_TEST_ASSERT(inputTestValue == 5, "Input value changed.");
VTKM_TEST_ASSERT(outputTestValue == inputTestValue + 100 + 30,
"Output value not set right.");
std::cout << " Try return value." << std::endl;
inputTestValue = 6;
outputTestValue = 0xDEADDEAD;
vtkm::exec::internal::detail::DoWorkletInvokeFunctor(
TestWorkletProxy(),
vtkm::internal::make_Invocation<1>(execObjects,
TestControlInterface(),
TestExecutionInterface2()),
2);
VTKM_TEST_ASSERT(inputTestValue == 6, "Input value changed.");
VTKM_TEST_ASSERT(outputTestValue == inputTestValue + 200 + 30*2,
"Output value not set right.");
}
void TestNormalFunctorInvoke()
{
std::cout << "Testing normal worklet invoke." << std::endl;
vtkm::Id inputTestValue;
vtkm::Id outputTestValue;
vtkm::internal::FunctionInterface<void(TestExecObject,TestExecObject)> execObjects =
vtkm::internal::make_FunctionInterface<void>(TestExecObject(&inputTestValue),
TestExecObject(&outputTestValue));
std::cout << " Try void return." << std::endl;
inputTestValue = 5;
outputTestValue = 0xDEADDEAD;
typedef vtkm::exec::internal::WorkletInvokeFunctor<TestWorkletProxy,InvocationType1> WorkletInvokeFunctor1;
WorkletInvokeFunctor1 workletInvokeFunctor1 =
WorkletInvokeFunctor1(TestWorkletProxy(), InvocationType1(execObjects));
workletInvokeFunctor1(1);
VTKM_TEST_ASSERT(inputTestValue == 5, "Input value changed.");
VTKM_TEST_ASSERT(outputTestValue == inputTestValue + 100 + 30,
"Output value not set right.");
std::cout << " Try return value." << std::endl;
inputTestValue = 6;
outputTestValue = 0xDEADDEAD;
typedef vtkm::exec::internal::WorkletInvokeFunctor<TestWorkletProxy,InvocationType2> WorkletInvokeFunctor2;
WorkletInvokeFunctor2 workletInvokeFunctor2 =
WorkletInvokeFunctor2(TestWorkletProxy(), InvocationType2(execObjects));
workletInvokeFunctor2(2);
VTKM_TEST_ASSERT(inputTestValue == 6, "Input value changed.");
VTKM_TEST_ASSERT(outputTestValue == inputTestValue + 200 + 30*2,
"Output value not set right.");
}
void TestErrorFunctorInvoke()
{
std::cout << "Testing invoke with an error raised in the worklet." << std::endl;
vtkm::Id inputTestValue = 5;
vtkm::Id outputTestValue = 0xDEADDEAD;
vtkm::internal::FunctionInterface<void(TestExecObject,TestExecObject)> execObjects =
vtkm::internal::make_FunctionInterface<void>(TestExecObject(&inputTestValue),
TestExecObject(&outputTestValue));
typedef vtkm::exec::internal::WorkletInvokeFunctor<TestWorkletErrorProxy,InvocationType1> WorkletInvokeFunctor1;
WorkletInvokeFunctor1 workletInvokeFunctor1 =
WorkletInvokeFunctor1(TestWorkletErrorProxy(), InvocationType1(execObjects));
char message[1024];
vtkm::exec::internal::ErrorMessageBuffer errorMessage(message, 1024);
workletInvokeFunctor1.SetErrorMessageBuffer(errorMessage);
workletInvokeFunctor1(1);
VTKM_TEST_ASSERT(errorMessage.IsErrorRaised(), "Error not raised correctly.");
VTKM_TEST_ASSERT(message == std::string(ERROR_MESSAGE),
"Got wrong error message.");
}
void TestWorkletInvokeFunctor()
{
TestDoWorkletInvoke();
TestNormalFunctorInvoke();
TestErrorFunctorInvoke();
}
} // anonymous namespace
int UnitTestWorkletInvokeFunctor(int, char *[])
{
return vtkm::testing::Testing::Run(TestWorkletInvokeFunctor);
}
......@@ -625,7 +625,7 @@ public:
template<typename TransformFunctor, typename FinishFunctor>
VTKM_CONT_EXPORT
void DynamicTransformCont(const TransformFunctor &transform,
const FinishFunctor &finish) {
const FinishFunctor &finish) const {
typedef detail::FunctionInterfaceDynamicTransformContContinue<
FunctionSignature,
ResultType(),
......@@ -637,7 +637,7 @@ public:
ContinueFunctorType(*this, emptyInterface, transform, finish);
continueFunctor.DoNextTransform(emptyInterface);
this->Result = emptyInterface.GetReturnValueSafe();
// this->Result = emptyInterface.GetReturnValueSafe();
}
/// \brief Applies a function to all the parameters.
......@@ -682,7 +682,7 @@ class FunctionInterfaceDynamicTransformContContinue
{
public:
FunctionInterfaceDynamicTransformContContinue(
vtkm::internal::FunctionInterface<OriginalFunction> &originalInterface,
const vtkm::internal::FunctionInterface<OriginalFunction> &originalInterface,
vtkm::internal::FunctionInterface<NewFunction> &newInterface,
const TransformFunctor &transform,
const FinishFunctor &finish)
......@@ -740,7 +740,7 @@ public:
}
private:
vtkm::internal::FunctionInterface<OriginalFunction> &OriginalInterface;
const vtkm::internal::FunctionInterface<OriginalFunction> &OriginalInterface;
vtkm::internal::FunctionInterface<NewFunction> &NewInterface;
const TransformFunctor &Transform;
const FinishFunctor &Finish;
......
......@@ -32,16 +32,34 @@ namespace internal {
/// worklet. \c Invocation is a class that manages all these types.
///
template<typename _ParameterInterface,
typename _ControlInterface,
typename _ExecutionInterface,
vtkm::IdComponent _InputDomainIndex>
struct Invocation
{
/// \brief The types of the parameters
///
/// \c ParameterInterface is (expected to be) a FunctionInterface class that
/// lists the types of the parameters for the invocation.
/// \c ParameterInterface is (expected to be) a \c FunctionInterface class
/// that lists the types of the parameters for the invocation.
///
typedef _ParameterInterface ParameterInterface;
/// \brief The tags of the \c ControlSignature.
///
/// \c ControlInterface is (expected to be) a \c FunctionInterface class that
/// represents the \c ControlSignature of a worklet (although dispatchers
/// might modify the control signature to provide auxiliary information).
///
typedef _ControlInterface ControlInterface;