@ -6,10 +6,158 @@
# include "../test_precomp.hpp"
# include "../gapi_mock_kernels.hpp"
namespace opencv_test
{
namespace
{
class GMockExecutable final : public cv : : gimpl : : GIslandExecutable
{
virtual inline bool canReshape ( ) const override {
return m_priv - > m_can_reshape ;
}
virtual void reshape ( ade : : Graph & , const GCompileArgs & ) override
{
m_priv - > m_reshape_counter + + ;
}
virtual void handleNewStream ( ) override { }
virtual void run ( std : : vector < InObj > & & , std : : vector < OutObj > & & ) { }
virtual bool allocatesOutputs ( ) const override
{
return true ;
}
virtual cv : : RMat allocate ( const cv : : GMatDesc & ) const override
{
m_priv - > m_allocate_counter + + ;
return cv : : RMat ( ) ;
}
// NB: GMockBackendImpl creates new unique_ptr<GMockExecutable>
// on every compile call. Need to share counters between instances in order
// to validate it in tests.
struct Priv
{
bool m_can_reshape ;
int m_reshape_counter ;
int m_allocate_counter ;
} ;
std : : shared_ptr < Priv > m_priv ;
public :
GMockExecutable ( bool can_reshape = true )
: m_priv ( new Priv { can_reshape , 0 , 0 } )
{
} ;
void setReshape ( bool can_reshape ) { m_priv - > m_can_reshape = can_reshape ; }
int getReshapeCounter ( ) const { return m_priv - > m_reshape_counter ; }
int getAllocateCounter ( ) const { return m_priv - > m_allocate_counter ; }
} ;
class GMockBackendImpl final : public cv : : gapi : : GBackend : : Priv
{
virtual void unpackKernel ( ade : : Graph & ,
const ade : : NodeHandle & ,
const cv : : GKernelImpl & ) override { }
virtual EPtr compile ( const ade : : Graph & ,
const cv : : GCompileArgs & ,
const std : : vector < ade : : NodeHandle > & ) const override
{
+ + m_compile_counter ;
return EPtr { new GMockExecutable ( m_exec ) } ;
}
mutable int m_compile_counter = 0 ;
GMockExecutable m_exec ;
virtual bool controlsMerge ( ) const override {
return true ;
}
virtual bool allowsMerge ( const cv : : gimpl : : GIslandModel : : Graph & ,
const ade : : NodeHandle & ,
const ade : : NodeHandle & ,
const ade : : NodeHandle & ) const override {
return false ;
}
public :
GMockBackendImpl ( const GMockExecutable & exec ) : m_exec ( exec ) { } ;
int getCompileCounter ( ) const { return m_compile_counter ; }
} ;
class GMockFunctor : public gapi : : cpu : : GOCVFunctor
{
public :
GMockFunctor ( cv : : gapi : : GBackend backend ,
const char * id ,
const Meta & meta ,
const Impl & impl )
: gapi : : cpu : : GOCVFunctor ( id , meta , impl ) , m_backend ( backend )
{
}
cv : : gapi : : GBackend backend ( ) const override { return m_backend ; }
private :
cv : : gapi : : GBackend m_backend ;
} ;
template < typename K , typename Callable >
GMockFunctor mock_kernel ( const cv : : gapi : : GBackend & backend , Callable c )
{
using P = cv : : detail : : OCVCallHelper < Callable , typename K : : InArgs , typename K : : OutArgs > ;
return GMockFunctor { backend
, K : : id ( )
, & K : : getOutMeta
, std : : bind ( & P : : callFunctor , std : : placeholders : : _1 , c )
} ;
}
void dummyFooImpl ( const cv : : Mat & , cv : : Mat & ) { } ;
void dummyBarImpl ( const cv : : Mat & , const cv : : Mat & , cv : : Mat & ) { } ;
struct GExecutorReshapeTest : public : : testing : : Test
{
GExecutorReshapeTest ( )
: comp ( [ ] ( ) {
cv : : GMat in ;
cv : : GMat out = I : : Bar : : on ( I : : Foo : : on ( in ) , in ) ;
return cv : : GComputation ( in , out ) ;
} )
{
backend_impl1 = std : : make_shared < GMockBackendImpl > ( island1 ) ;
backend1 = cv : : gapi : : GBackend { backend_impl1 } ;
backend_impl2 = std : : make_shared < GMockBackendImpl > ( island2 ) ;
backend2 = cv : : gapi : : GBackend { backend_impl2 } ;
auto kernel1 = mock_kernel < I : : Foo > ( backend1 , dummyFooImpl ) ;
auto kernel2 = mock_kernel < I : : Bar > ( backend2 , dummyBarImpl ) ;
pkg = cv : : gapi : : kernels ( kernel1 , kernel2 ) ;
in_mat1 = cv : : Mat : : eye ( 32 , 32 , CV_8UC1 ) ;
in_mat2 = cv : : Mat : : eye ( 64 , 64 , CV_8UC1 ) ;
}
cv : : GComputation comp ;
GMockExecutable island1 ;
std : : shared_ptr < GMockBackendImpl > backend_impl1 ;
cv : : gapi : : GBackend backend1 ;
GMockExecutable island2 ;
std : : shared_ptr < GMockBackendImpl > backend_impl2 ;
cv : : gapi : : GBackend backend2 ;
cv : : gapi : : GKernelPackage pkg ;
cv : : Mat in_mat1 , in_mat2 , out_mat ; ;
} ;
} // anonymous namespace
// FIXME: avoid code duplication
// The below graph and config is taken from ComplexIslands test suite
TEST ( GExecutor , SmokeTest )
@ -77,6 +225,75 @@ TEST(GExecutor, SmokeTest)
// with breakdown worked)
}
TEST_F ( GExecutorReshapeTest , ReshapeInsteadOfRecompile )
{
// NB: Initial state
EXPECT_EQ ( 0 , backend_impl1 - > getCompileCounter ( ) ) ;
EXPECT_EQ ( 0 , backend_impl2 - > getCompileCounter ( ) ) ;
EXPECT_EQ ( 0 , island1 . getReshapeCounter ( ) ) ;
EXPECT_EQ ( 0 , island2 . getReshapeCounter ( ) ) ;
// NB: First compilation.
comp . apply ( cv : : gin ( in_mat1 ) , cv : : gout ( out_mat ) , cv : : compile_args ( pkg ) ) ;
EXPECT_EQ ( 1 , backend_impl1 - > getCompileCounter ( ) ) ;
EXPECT_EQ ( 1 , backend_impl2 - > getCompileCounter ( ) ) ;
EXPECT_EQ ( 0 , island1 . getReshapeCounter ( ) ) ;
EXPECT_EQ ( 0 , island2 . getReshapeCounter ( ) ) ;
// NB: GMockBackendImpl implements "reshape" method,
// so it won't be recompiled if the meta is changed.
comp . apply ( cv : : gin ( in_mat2 ) , cv : : gout ( out_mat ) , cv : : compile_args ( pkg ) ) ;
EXPECT_EQ ( 1 , backend_impl1 - > getCompileCounter ( ) ) ;
EXPECT_EQ ( 1 , backend_impl2 - > getCompileCounter ( ) ) ;
EXPECT_EQ ( 1 , island1 . getReshapeCounter ( ) ) ;
EXPECT_EQ ( 1 , island2 . getReshapeCounter ( ) ) ;
}
TEST_F ( GExecutorReshapeTest , OneBackendNotReshapable )
{
// NB: Make first island not reshapable
island1 . setReshape ( false ) ;
// NB: Initial state
EXPECT_EQ ( 0 , backend_impl1 - > getCompileCounter ( ) ) ;
EXPECT_EQ ( 0 , island1 . getReshapeCounter ( ) ) ;
EXPECT_EQ ( 0 , backend_impl2 - > getCompileCounter ( ) ) ;
EXPECT_EQ ( 0 , island2 . getReshapeCounter ( ) ) ;
// NB: First compilation.
comp . apply ( cv : : gin ( in_mat1 ) , cv : : gout ( out_mat ) , cv : : compile_args ( pkg ) ) ;
EXPECT_EQ ( 1 , backend_impl1 - > getCompileCounter ( ) ) ;
EXPECT_EQ ( 1 , backend_impl2 - > getCompileCounter ( ) ) ;
EXPECT_EQ ( 0 , island1 . getReshapeCounter ( ) ) ;
EXPECT_EQ ( 0 , island2 . getReshapeCounter ( ) ) ;
// NB: Since one of islands isn't reshapable
// the entire graph isn't reshapable as well.
comp . apply ( cv : : gin ( in_mat2 ) , cv : : gout ( out_mat ) , cv : : compile_args ( pkg ) ) ;
EXPECT_EQ ( 2 , backend_impl1 - > getCompileCounter ( ) ) ;
EXPECT_EQ ( 2 , backend_impl2 - > getCompileCounter ( ) ) ;
EXPECT_EQ ( 0 , island1 . getReshapeCounter ( ) ) ;
EXPECT_EQ ( 0 , island2 . getReshapeCounter ( ) ) ;
}
TEST_F ( GExecutorReshapeTest , ReshapeCallAllocate )
{
// NB: Initial state
EXPECT_EQ ( 0 , island1 . getAllocateCounter ( ) ) ;
EXPECT_EQ ( 0 , island1 . getReshapeCounter ( ) ) ;
// NB: First compilation.
comp . apply ( cv : : gin ( in_mat1 ) , cv : : gout ( out_mat ) , cv : : compile_args ( pkg ) ) ;
EXPECT_EQ ( 1 , island1 . getAllocateCounter ( ) ) ;
EXPECT_EQ ( 0 , island1 . getReshapeCounter ( ) ) ;
// NB: The entire graph is reshapable, so it won't be recompiled, but reshaped.
// Check that reshape call "allocate" to reallocate buffers.
comp . apply ( cv : : gin ( in_mat2 ) , cv : : gout ( out_mat ) , cv : : compile_args ( pkg ) ) ;
EXPECT_EQ ( 2 , island1 . getAllocateCounter ( ) ) ;
EXPECT_EQ ( 1 , island1 . getReshapeCounter ( ) ) ;
}
// FIXME: Add explicit tests on GMat/GScalar/GArray<T> being connectors
// between executed islands