Tools for conditional compilation (#3169)

* Tools for conditional compilation

* Unit tests for conditional compilation & Refactoring

* Fix for MSVC selective build macros

* Unit tests for conditional compilation in analysys mode

* Code generation for selective build is hidden inside CMake

* Comments for conditional compilation options
This commit is contained in:
Vladislav Volkov 2020-11-25 06:43:35 +03:00 committed by GitHub
parent 5ce8946864
commit 1f96ddfbf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 910 additions and 4 deletions

View File

@ -54,3 +54,9 @@ ie_dependent_option (ENABLE_FASTER_BUILD "Enable build features (PCH, UNITY) to
# Type of build, we add this as an explicit option to default it to ON
# FIXME: Ah this moment setting this to OFF will only build ngraph a static library
ie_option (BUILD_SHARED_LIBS "Build as a shared library" ON)
ie_option_enum(SELECTIVE_BUILD "Enable OpenVINO conditional compilation or statistics collection. \
In case SELECTIVE_BUILD is enabled, the SELECTIVE_BUILD_STAT variable should contain the path to the collected InelSEAPI statistics. \
Usage: -DSELECTIVE_BUILD=ON -DSELECTIVE_BUILD_STAT=/path/*.csv" OFF
ALLOWED_VALUES ON OFF COLLECT)

View File

@ -16,6 +16,21 @@ macro (ie_dependent_option variable description def_value condition fallback_val
list(APPEND IE_OPTIONS ${variable})
endmacro()
macro (ie_option_enum variable description value)
set(OPTIONS)
set(ONE_VALUE_ARGS)
set(MULTI_VALUE_ARGS ALLOWED_VALUES)
cmake_parse_arguments(IE_OPTION_ENUM "${OPTIONS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN})
if(NOT ${value} IN_LIST IE_OPTION_ENUM_ALLOWED_VALUES)
message(FATAL_ERROR "variable must be one of ${IE_OPTION_ENUM_ALLOWED_VALUES}")
endif()
list(APPEND IE_OPTIONS ${variable})
set(${variable} ${value} CACHE STRING "${description}")
endmacro()
function (print_enabled_features)
message(STATUS "Inference Engine enabled features: ")
message(STATUS "")

View File

@ -167,6 +167,17 @@ macro(ie_add_compiler_flags)
endforeach()
endmacro()
#
# Forced includes certain header file to all target source files
#
function(ov_force_include target scope header_file)
if(MSVC)
target_compile_options(${target} ${scope} /FI"${header_file}")
else()
target_compile_options(${target} ${scope} -include "${header_file}")
endif()
endfunction()
#
# Compilation and linker flags
#

View File

@ -83,7 +83,7 @@ target_include_directories(${TARGET_NAME}_plugin_api INTERFACE
$<TARGET_PROPERTY:${TARGET_NAME}_preproc,INTERFACE_INCLUDE_DIRECTORIES>
${PUBLIC_HEADERS_DIR})
target_link_libraries(${TARGET_NAME}_plugin_api INTERFACE openvino::itt)
target_link_libraries(${TARGET_NAME}_plugin_api INTERFACE openvino::itt openvino::conditional_compilation)
set_ie_threading_interface_for(${TARGET_NAME}_plugin_api)
@ -138,7 +138,7 @@ ie_add_vs_version_file(NAME ${TARGET_NAME}
set_ie_threading_interface_for(${TARGET_NAME})
target_link_libraries(${TARGET_NAME} PRIVATE pugixml openvino::itt ${CMAKE_DL_LIBS} Threads::Threads
target_link_libraries(${TARGET_NAME} PRIVATE pugixml openvino::itt openvino::conditional_compilation ${CMAKE_DL_LIBS} Threads::Threads
${NGRAPH_LIBRARIES} inference_engine_transformations)
target_include_directories(${TARGET_NAME} INTERFACE ${PUBLIC_HEADERS_DIR}
@ -173,7 +173,7 @@ if(WIN32)
set_target_properties(${TARGET_NAME}_s PROPERTIES COMPILE_PDB_NAME ${TARGET_NAME}_s)
endif()
target_link_libraries(${TARGET_NAME}_s PRIVATE openvino::itt ${CMAKE_DL_LIBS} ${NGRAPH_LIBRARIES}
target_link_libraries(${TARGET_NAME}_s PRIVATE openvino::itt openvino::conditional_compilation ${CMAKE_DL_LIBS} ${NGRAPH_LIBRARIES}
inference_engine_transformations
PUBLIC pugixml)

View File

@ -12,6 +12,7 @@ set(LINK_LIBRARIES
ngraphFunctions
inference_engine_transformations
openvino::itt
openvino::conditional_compilation
)
set(DEPENDENCIES
mock_engine

View File

@ -0,0 +1,141 @@
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#ifdef SELECTIVE_BUILD_ANALYZER
# define SELECTIVE_BUILD_ANALYZER_ON
# undef SELECTIVE_BUILD_ANALYZER
#elif defined(SELECTIVE_BUILD)
# define SELECTIVE_BUILD_ON
# undef SELECTIVE_BUILD
#endif
#define SELECTIVE_BUILD
#include <openvino/cc/factory.h>
namespace {
OV_CC_DOMAINS(CCTests);
template<typename T>
struct TestTemplateClass;
template<>
struct TestTemplateClass<int> {
void operator()(int &v) {
v = 42;
}
};
template<>
struct TestTemplateClass<bool> {
void operator()(int &v) {
v = 43;
}
};
template<>
struct TestTemplateClass<float> {
void operator()(int &v) {
v = 44;
}
};
struct TestNodeBase {
TestNodeBase(int k, int v)
: key(k)
, value(v) {}
virtual ~TestNodeBase() = default;
int key;
int value;
};
template<int N>
struct TestNode : public TestNodeBase {
TestNode(int value)
: TestNodeBase(N, value) {}
};
} // namespace
TEST(ConditionalCompilationTests, SimpleScope) {
#define CCTests_Scope0 1
int n = 0;
// Simple scope is enabled
OV_SCOPE(CCTests, Scope0, n = 42;);
EXPECT_EQ(n, 42);
// Simple scope is disabled
OV_SCOPE(CCTests, Scope1, n = 0;);
EXPECT_EQ(n, 42);
#undef CCTests_Scope0
}
TEST(ConditionalCompilationTests, SwitchCase) {
// Cases 0 and 2 are enabled
#define CCTests_TestTemplateClass 1
#define CCTests_TestTemplateClass_cases OV_CASE(0, int), OV_CASE(2, float)
int n = 0;
OV_SWITCH(CCTests, TestTemplateClass, n, 0,
OV_CASE(0, int),
OV_CASE(1, bool),
OV_CASE(2, float));
EXPECT_EQ(n, 42);
OV_SWITCH(CCTests, TestTemplateClass, n, 1,
OV_CASE(0, int),
OV_CASE(1, bool),
OV_CASE(2, float));
EXPECT_EQ(n, 42);
OV_SWITCH(CCTests, TestTemplateClass, n, 2,
OV_CASE(0, int),
OV_CASE(1, bool),
OV_CASE(2, float));
EXPECT_EQ(n, 44);
#undef CCTests_TestTemplateClass
#undef CCTests_TestTemplateClass_cases
}
TEST(ConditionalCompilationTests, Factory) {
#define CCTests_TestNode0 1
#define CCTests_TestNode1 0
#define CCTests_TestNode2 1
openvino::cc::Factory<int, TestNodeBase*(int)> testFactory("TestFactory");
testFactory.registerNodeIfRequired(CCTests, TestNode0, 0, TestNode<0>);
testFactory.registerNodeIfRequired(CCTests, TestNode1, 1, TestNode<1>);
testFactory.registerNodeIfRequired(CCTests, TestNode2, 2, TestNode<2>);
TestNodeBase *node0 = testFactory.createNodeIfRegistered(CCTests, 0, 42);
TestNodeBase *node1 = testFactory.createNodeIfRegistered(CCTests, 1, 43);
TestNodeBase *node2 = testFactory.createNodeIfRegistered(CCTests, 2, 44);
EXPECT_TRUE(node0 && node0->key == 0 && node0->value == 42);
EXPECT_TRUE(!node1);
EXPECT_TRUE(node2 && node2->key == 2 && node2->value == 44);
delete node0;
delete node1;
delete node2;
#undef CCTests_TestNode0
#undef CCTests_TestNode1
#undef CCTests_TestNode2
}
#undef SELECTIVE_BUILD
#ifdef SELECTIVE_BUILD_ANALYZER_ON
# define SELECTIVE_BUILD_ANALYZER
#elif defined(SELECTIVE_BUILD_ON)
# define SELECTIVE_BUILD
#endif

View File

@ -0,0 +1,108 @@
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#ifdef SELECTIVE_BUILD_ANALYZER
# define SELECTIVE_BUILD_ANALYZER_ON
# undef SELECTIVE_BUILD_ANALYZER
#elif defined(SELECTIVE_BUILD)
# define SELECTIVE_BUILD_ON
# undef SELECTIVE_BUILD
#endif
#define SELECTIVE_BUILD_ANALYZER
#include <openvino/cc/factory.h>
namespace {
OV_CC_DOMAINS(CCTests);
template<typename T>
struct TestTemplateClass;
template<>
struct TestTemplateClass<int> {
void operator()(int &v) {
v = 42;
}
};
template<>
struct TestTemplateClass<bool> {
void operator()(int &v) {
v = 43;
}
};
template<>
struct TestTemplateClass<float> {
void operator()(int &v) {
v = 44;
}
};
struct TestNodeBase {
TestNodeBase(int k, int v)
: key(k)
, value(v) {}
virtual ~TestNodeBase() = default;
int key;
int value;
};
template<int N>
struct TestNode : public TestNodeBase {
TestNode(int value)
: TestNodeBase(N, value) {}
};
} // namespace
TEST(ConditionalCompilationTests, SimpleScopeAnalysys) {
int n = 0;
OV_SCOPE(CCTests, Scope0, n = 42;);
EXPECT_EQ(n, 42);
OV_SCOPE(CCTests, Scope1, n = 43;);
EXPECT_EQ(n, 43);
}
TEST(ConditionalCompilationTests, SwitchCaseAnalysys) {
int n = 0;
OV_SWITCH(CCTests, TestTemplateClass, n, 0,
OV_CASE(0, int),
OV_CASE(1, bool),
OV_CASE(2, float));
EXPECT_EQ(n, 42);
}
TEST(ConditionalCompilationTests, FactoryAnalysys) {
openvino::cc::Factory<int, TestNodeBase*(int)> testFactory("TestFactory");
testFactory.registerNodeIfRequired(CCTests, TestNode0, 0, TestNode<0>);
testFactory.registerNodeIfRequired(CCTests, TestNode1, 1, TestNode<1>);
testFactory.registerNodeIfRequired(CCTests, TestNode2, 2, TestNode<2>);
TestNodeBase *node0 = testFactory.createNodeIfRegistered(CCTests, 0, 42);
TestNodeBase *node1 = testFactory.createNodeIfRegistered(CCTests, 1, 43);
TestNodeBase *node2 = testFactory.createNodeIfRegistered(CCTests, 2, 44);
EXPECT_TRUE(node0 && node0->key == 0 && node0->value == 42);
EXPECT_TRUE(node1 && node1->key == 1 && node1->value == 43);
EXPECT_TRUE(node2 && node2->key == 2 && node2->value == 44);
delete node0;
delete node1;
delete node2;
}
#undef SELECTIVE_BUILD_ANALYZER
#ifdef SELECTIVE_BUILD_ANALYZER_ON
# define SELECTIVE_BUILD_ANALYZER
#elif defined(SELECTIVE_BUILD_ON)
# define SELECTIVE_BUILD
#endif

View File

@ -15,5 +15,6 @@
# ******************************************************************************
add_subdirectory(itt)
add_subdirectory(conditional_compilation)
openvino_developer_export_targets(openvino::itt)
openvino_developer_export_targets(openvino::itt openvino::conditional_compilation)

View File

@ -0,0 +1,46 @@
# ******************************************************************************
# Copyright 2017-2020 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ******************************************************************************
set(TARGET_NAME conditional_compilation)
add_library(${TARGET_NAME} INTERFACE)
add_library(openvino::conditional_compilation ALIAS ${TARGET_NAME})
target_link_libraries(${TARGET_NAME} INTERFACE openvino::itt)
target_include_directories(${TARGET_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
if(SELECTIVE_BUILD STREQUAL "COLLECT")
target_compile_definitions(${TARGET_NAME} INTERFACE SELECTIVE_BUILD_ANALYZER)
elseif(SELECTIVE_BUILD STREQUAL "ON")
if(NOT DEFINED SELECTIVE_BUILD_STAT)
message(FATAL_ERROR "In case SELECTIVE_BUILD is enabled, the SELECTIVE_BUILD_STAT variable should contain the path to the collected InelSEAPI statistics.\
Usage: -DSELECTIVE_BUILD=ON -DSELECTIVE_BUILD_STAT=/path/*.csv")
endif()
target_compile_definitions(${TARGET_NAME} INTERFACE SELECTIVE_BUILD)
set(GENERATED_HEADER ${CMAKE_CURRENT_BINARY_DIR}/conditional_compilation_gen.h)
set(GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/scripts/ccheader.py)
add_custom_command(OUTPUT ${GENERATED_HEADER}
COMMAND python3 ${GENERATOR} --stat ${SELECTIVE_BUILD_STAT} --out ${GENERATED_HEADER})
add_custom_target(conditional_compilation_gen DEPENDS ${GENERATED_HEADER})
add_dependencies(${TARGET_NAME} conditional_compilation_gen)
ov_force_include(${TARGET_NAME} INTERFACE ${GENERATED_HEADER})
endif()

View File

@ -0,0 +1,144 @@
//*****************************************************************************
// Copyright 2017-2020 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************
#pragma once
#include "selective_build.h"
#include <string>
#include <functional>
#include <type_traits>
#include <unordered_map>
namespace openvino
{
namespace cc
{
template<typename Key, typename T>
class Factory;
template<typename Key, typename T, typename ...Args>
class Factory<Key, T(Args...)> {
Factory(Factory const&) = delete;
Factory& operator=(Factory const&) = delete;
public:
using builder_t = std::function<T(Args...)>;
Factory(const std::string & name)
: name(name) {}
#ifdef SELECTIVE_BUILD
#define registerNodeIfRequired(Module, Name, key, Impl) \
OV_CC_EXPAND(OV_CC_CAT(registerImpl, OV_CC_SCOPE_IS_ENABLED(OV_CC_CAT3(Module, _, Name)))<Impl>(key))
#define createNodeIfRegistered(Module, key, ...) createImpl(key, __VA_ARGS__)
template<typename Impl>
void registerImpl0(const Key &) {
}
template<typename Impl>
void registerImpl1(const Key & key) {
builders[key] = [](Args... args) -> T {
Impl *impl = new Impl(args...);
return static_cast<T>(impl);
};
}
T createImpl(const Key & key, Args... args) {
auto builder = builders.find(key);
if (builder != builders.end()) {
return builder->second(args...);
}
return nullptr;
}
#elif defined(SELECTIVE_BUILD_ANALYZER)
#define registerNodeIfRequired(Module, Name, key, Impl) registerImpl<OV_CC_CAT(FACTORY_, Module), Impl>(key, OV_CC_TOSTRING(Name))
#define createNodeIfRegistered(Module, key, ...) createImpl<OV_CC_CAT(FACTORY_, Module)>(key, __VA_ARGS__)
template<openvino::itt::domain_t(*domain)(), typename Impl>
void registerImpl(const Key & key, const char *typeName) {
const std::string task_name = "REG$" + name + "$" + to_string(key) + "$" + typeName;
openvino::itt::ScopedTask<domain> task(openvino::itt::handle(task_name));
builders[key] = [](Args... args) -> T {
Impl *impl = new Impl(args...);
return static_cast<T>(impl);
};
}
template<openvino::itt::domain_t(*domain)()>
T createImpl(const Key & key, Args... args) {
auto builder = builders.find(key);
if (builder != builders.end()) {
const std::string task_name = "CREATE$" + name + "$" + to_string(key);
openvino::itt::ScopedTask<domain> task(openvino::itt::handle(task_name));
return builder->second(args...);
}
return nullptr;
}
#else
#define registerNodeIfRequired(Module, Name, key, Impl) registerImpl<Impl>(key)
#define createNodeIfRegistered(Module, key, ...) createImpl(key, __VA_ARGS__)
template<typename Impl>
void registerImpl(const Key & key) {
builders[key] = [](Args... args) -> T {
Impl *impl = new Impl(args...);
return static_cast<T>(impl);
};
}
T createImpl(const Key & key, Args... args) {
auto builder = builders.find(key);
if (builder != builders.end()) {
return builder->second(args...);
}
return nullptr;
}
#endif
template<typename Fn>
void foreach(Fn fn) const {
for (auto itm : builders)
fn(itm);
}
size_t size() const noexcept {
return builders.size();
}
private:
const std::string & to_string(const std::string & str) const noexcept {
return str;
}
template<typename V,
typename std::enable_if<std::is_enum<V>::value, bool>::type = true>
std::string to_string(V val) const {
return std::to_string(static_cast<int>(val));
}
template<typename V,
typename std::enable_if<!std::is_enum<V>::value, bool>::type = true>
std::string to_string(V val) const {
return std::to_string(val);
}
using map_t = std::unordered_map<Key, builder_t>;
const std::string name;
map_t builders;
};
}
}

View File

@ -0,0 +1,265 @@
//*****************************************************************************
// Copyright 2017-2020 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************
#pragma once
/*
This file contains a useful API for analyzing OpenVINO sources
and enabling or disabling some regions.
Three working modes are currently supported.
* SELECTIVE_BUILD_ANALYZER This macro enables analysis mode for annotated code regions.
* When the process completes, a new C++ header file is created
* that contains macros for enabling active regions. This file
* should be included in all analysed C++ files.
*
* SELECTIVE_BUILD This mode disables inactive areas of the code using the result
* of the analysis step.
*
* No definitions The default behavior is keept if no SELECTIVE_BUILD* macros are defined,
* i.e all features of the OpenVINO are enabled.
*
* Prerequisites:
* Before using macros for code annotation,domains for conditional
* compilation should be defined in module namespace.
*
* OV_CC_DOMAINS(MyModule);
*
* An example of using annotation:
*
* I. Any C++ code block:
* OV_SCOPE(MyModule, ScopeName,
* // Any C++ code.
* cout << "Hello world!";
* );
*
* II. Template class instantiation using switch-case:
*
* struct Context { ... };
*
* template<typename T>
* struct SomeTemplateClass {
* void operator()(Context &context) {
* // Any C++ code.
* cout << "Hello world!";
* }
* };
*
* auto key = Precision::U8;
* Context context;
*
* OV_SWITCH(MyModule, SomeTemplateClass, context, key,
* OV_CASE(Precision::U8, uint8_t),
* OV_CASE(Precision::I8, int8_t),
* OV_CASE(Precision::FP32, float));
*
*/
#include <openvino/itt.hpp>
#ifdef SELECTIVE_BUILD_ANALYZER
#include <string>
#endif
#include <utility>
#include <tuple>
namespace openvino
{
namespace cc
{
#ifndef SELECTIVE_BUILD_ANALYZER
namespace internal
{
template<typename C, typename T>
struct case_wrapper {
using type = T;
const C value {};
case_wrapper(C && val)
: value(std::forward<C>(val))
{}
};
template<typename T, typename C>
case_wrapper<C, T> make_case_wrapper(C && val) {
return case_wrapper<C, T>(std::forward<C>(val));
}
template<template<typename...> class Fn, typename Ctx, typename T, typename Case>
bool match(Ctx && ctx, T && val, Case && cs) {
const bool is_matched = val == cs.value;
if (is_matched)
Fn<typename Case::type>()(std::forward<Ctx>(ctx));
return is_matched;
}
template<template<typename...> class Fn, typename Ctx, typename T, typename Case, typename ...Cases>
bool match(Ctx && ctx, T && val, Case && cs, Cases&&... cases) {
if (match<Fn>(std::forward<Ctx>(ctx), std::forward<T>(val), std::forward<Case>(cs)))
return true;
return match<Fn>(std::forward<Ctx>(ctx), std::forward<T>(val), std::forward<Cases>(cases)...);
}
} // namespace internal
#endif
// Macros for names concatenation
#define OV_CC_CAT_(x, y) x ## y
#define OV_CC_CAT(x, y) OV_CC_CAT_(x, y)
#define OV_CC_CAT3_(x, y, z) x ## y ## z
#define OV_CC_CAT3(x, y, z) OV_CC_CAT3_(x, y, z)
#define OV_CC_CAT4_(x, y, z, w) x ## y ## z ## w
#define OV_CC_CAT4(x, y, z, w) OV_CC_CAT4_(x, y, z, w)
// Expand macro argument
#define OV_CC_EXPAND(x) x
// Macros for string conversion
#define OV_CC_TOSTRING(...) OV_CC_TOSTRING_(__VA_ARGS__)
#define OV_CC_TOSTRING_(...) #__VA_ARGS__
#ifdef SELECTIVE_BUILD_ANALYZER // OpenVINO analysis
#define OV_CC_DOMAINS(Module) \
OV_ITT_DOMAIN(OV_CC_CAT(SIMPLE_, Module)); /* Domain for simple scope surrounded by ifdefs */ \
OV_ITT_DOMAIN(OV_CC_CAT(SWITCH_, Module)); /* Domain for switch/cases */ \
OV_ITT_DOMAIN(OV_CC_CAT(FACTORY_, Module)); /* Domain for factories */
namespace internal
{
template<typename C, typename T>
struct case_wrapper {
using type = T;
const C value {};
const char *name = nullptr;
case_wrapper(C && val, const char *name)
: value(std::forward<C>(val))
, name(name)
{}
};
template<typename T, typename C>
case_wrapper<C, T> make_case_wrapper(C && val, const char *name) {
return case_wrapper<C, T>(std::forward<C>(val), name);
}
template<openvino::itt::domain_t(*domain)(),
template<typename...> class Fn,
typename Ctx,
typename T,
typename Case>
bool match(char const *region, Ctx && ctx, T && val, Case && cs) {
const bool is_matched = val == cs.value;
if (is_matched) {
openvino::itt::ScopedTask<domain> task(
openvino::itt::handle<struct OV_CC_CAT(Task_, __LINE__)>(
std::string(region) + "$" + cs.name));
Fn<typename Case::type>()(std::forward<Ctx>(ctx));
}
return is_matched;
}
template<openvino::itt::domain_t(*domain)(),
template<typename...> class Fn,
typename Ctx,
typename T,
typename Case, typename ...Cases>
bool match(char const *region, Ctx && ctx, T && val, Case && cs, Cases&&... cases) {
if (match<domain, Fn>(region, std::forward<Ctx>(ctx), std::forward<T>(val), std::forward<Case>(cs)))
return true;
return match<domain, Fn>(region, std::forward<Ctx>(ctx), std::forward<T>(val), std::forward<Cases>(cases)...);
}
} // namespace internal
#define OV_SCOPE(Module, region, ...) \
OV_ITT_SCOPED_TASK(OV_CC_CAT(SIMPLE_, Module), OV_CC_TOSTRING(region)); \
__VA_ARGS__
#define OV_SWITCH(Module, fn, ctx, val, ...) \
openvino::cc::internal::match<OV_CC_CAT(SWITCH_, Module), fn> \
(OV_CC_TOSTRING(fn), ctx, val, __VA_ARGS__);
#define OV_CC_LBR (
#define OV_CC_RBR )
#define OV_CASE(Case, Type) \
openvino::cc::internal::make_case_wrapper<Type>(Case, OV_CC_TOSTRING(OV_CASE OV_CC_LBR Case, Type OV_CC_RBR))
#define OV_CASE2(Case1, Case2, Type1, Type2) \
openvino::cc::internal::make_case_wrapper<std::tuple<Type1, Type2>>( \
std::make_tuple(Case1, Case2), \
OV_CC_TOSTRING(OV_CASE2 OV_CC_LBR Case1, Case2, Type1, Type2 OV_CC_RBR))
#elif defined(SELECTIVE_BUILD) // OpenVINO selective build is enabled
#define OV_CC_DOMAINS(Module)
// Placeholder for first macro argument
#define OV_CC_SCOPE_ARG_PLACEHOLDER_1 0,
// This macro returns second argument, first argument is ignored
#define OV_CC_SCOPE_SECOND_ARG(...) OV_CC_EXPAND(OV_CC_SCOPE_SECOND_ARG_(__VA_ARGS__, 0))
#define OV_CC_SCOPE_SECOND_ARG_(...) OV_CC_EXPAND(OV_CC_SCOPE_SECOND_ARG_GET(__VA_ARGS__))
#define OV_CC_SCOPE_SECOND_ARG_GET(ignored, val, ...) val
// Return macro argument value
#define OV_CC_SCOPE_IS_ENABLED(x) OV_CC_SCOPE_IS_ENABLED1(x)
// Generate junk macro or {0, } sequence if val is 1
#define OV_CC_SCOPE_IS_ENABLED1(val) OV_CC_SCOPE_IS_ENABLED2(OV_CC_CAT(OV_CC_SCOPE_ARG_PLACEHOLDER_, val))
// Return second argument from possible sequences {1, 0}, {0, 1, 0}
#define OV_CC_SCOPE_IS_ENABLED2(arg1_or_junk) OV_CC_SCOPE_SECOND_ARG(arg1_or_junk 1, 0)
// Scope is disabled
#define OV_CC_SCOPE_0(...)
// Scope is enabled
#define OV_CC_SCOPE_1(...) __VA_ARGS__
#define OV_SCOPE(Module, region, ...) \
OV_CC_EXPAND(OV_CC_CAT(OV_CC_SCOPE_, OV_CC_SCOPE_IS_ENABLED(OV_CC_CAT3(Module, _, region)))(__VA_ARGS__))
// Switch is disabled
#define OV_CC_SWITCH_0(Module, fn, ctx, val)
// Switch is enabled
#define OV_CC_SWITCH_1(Module, fn, ctx, val) openvino::cc::internal::match<fn>(ctx, val, OV_CC_CAT4(Module, _, fn, _cases));
#define OV_SWITCH(Module, fn, ctx, val, ...) \
OV_CC_EXPAND(OV_CC_CAT(OV_CC_SWITCH_, OV_CC_SCOPE_IS_ENABLED(OV_CC_CAT3(Module, _, fn)))(Module, fn, ctx, val))
#define OV_CASE(Case, Type) openvino::cc::internal::make_case_wrapper<Type>(Case)
#define OV_CASE2(Case1, Case2, Type1, Type2) openvino::cc::internal::make_case_wrapper<std::tuple<Type1, Type2>>(std::make_tuple(Case1, Case2))
#else
#define OV_CC_DOMAINS(Module)
#define OV_SCOPE(Module, region, ...) __VA_ARGS__
#define OV_SWITCH(Module, fn, ctx, val, ...) \
openvino::cc::internal::match<fn>(ctx, val, __VA_ARGS__);
#define OV_CASE(Case, Type) openvino::cc::internal::make_case_wrapper<Type>(Case)
#define OV_CASE2(Case1, Case2, Type1, Type2) openvino::cc::internal::make_case_wrapper<std::tuple<Type1, Type2>>(std::make_tuple(Case1, Case2))
#endif
}
}

View File

@ -0,0 +1,168 @@
#!/usr/bin/env python3
# Copyright (c) 2020 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# The main purpose of this script is code generation for conditional compilation.
# After collecting statistics using IntelSEAPI, several CSV files are generated.
# This script can read these files and can produce header file which will contain
# definitions for enabled OpenVINO parts.
#
# Usage: ccheader.py [-h] --stat PATH[PATH...] [PATH[PATH...] ...] --out cc.h
#
# Mandatory arguments:
# --stat PATH[ PATH...] [PATH[ PATH...] ...]
# IntelSEAPI statistics files in CSV format
# --out cc.h C++ header file to be generated
import argparse, csv
from pathlib import Path
from abc import ABC, abstractmethod
Domain = ['SIMPLE_',
'SWITCH_',
'FACTORY_']
FILE_HEADER = "#pragma once\n\n"
FILE_FOOTER = "\n"
ENABLED_SCOPE_FMT = "#define %s_%s 1\n"
ENABLED_SWITCH_FMT = "#define %s_%s 1\n#define %s_%s_cases %s\n"
ENABLED_FACTORY_INSTANCE_FMT = "#define %s_%s 1\n"
class IScope(ABC):
@abstractmethod
def generate(self, f, module):
pass
class Scope(IScope):
def __init__(self, name):
self.name = name
def generate(self, f, module):
f.write(ENABLED_SCOPE_FMT % (module, self.name))
class Switch(IScope):
def __init__(self, name):
self.name = name
self.cases = set()
def case(self, val):
self.cases.add(val)
def generate(self, f, module):
f.write(ENABLED_SWITCH_FMT % (module, self.name, module, self.name, ', '.join(self.cases)))
class Factory(IScope):
def __init__(self, name):
self.name = name
self.registered = {}
self.created = set()
def register(self, id, name):
self.registered[id] = name
def create(self, id):
self.created.add(id)
def generate(self, f, module):
for id in self.created:
r = self.registered.get(id)
if r:
f.write(ENABLED_FACTORY_INSTANCE_FMT % (module, r))
class Module:
def __init__(self, name):
self.name = name
self.scopes = {}
def scope(self, name):
if name not in self.scopes:
self.scopes[name] = Scope(name)
return self.scopes.get(name)
def factory(self, name):
if name not in self.scopes:
self.scopes[name] = Factory(name)
return self.scopes.get(name)
def switch(self, name):
if name not in self.scopes:
self.scopes[name] = Switch(name)
return self.scopes.get(name)
def generate(self, f):
for _, scope in self.scopes.items():
scope.generate(f, self.name)
if self.scopes:
f.write("\n")
class Stat:
def __init__(self, files):
self.modules = {}
self.read(files)
def module(self, name):
if name not in self.modules:
self.modules[name] = Module(name)
return self.modules.get(name)
def read(self, files):
for stat in files:
with open(stat) as f:
reader = csv.reader(f)
rows = list(reader)
if rows:
# Scopes
scopes = list(filter(lambda row: row[0].startswith(Domain[0]), rows))
for row in scopes:
moduleName = row[0][len(Domain[0]):]
self.module(moduleName).scope(row[1])
# Switches
switches = list(map(lambda row: [row[0][len(Domain[1]):]] + row[1].strip().split('$'),
filter(lambda row: row[0].startswith(Domain[1]), rows)))
for switch in switches:
self.module(switch[0]).switch(switch[1]).case(switch[2])
# Factories
factories = list(map(lambda row: [row[0][len(Domain[2]):]] + row[1].strip().split('$'),
filter(lambda row: row[0].startswith(Domain[2]), rows)))
for reg in list(filter(lambda row: row[1] == 'REG', factories)):
self.module(reg[0]).factory(reg[2]).register(reg[3], reg[4])
for cre in list(filter(lambda row: row[1] == 'CREATE', factories)):
self.module(cre[0]).factory(cre[2]).create(cre[3])
def generate(self, out):
with open(out, 'w') as f:
f.write(FILE_HEADER)
for _, module in self.modules.items():
module.generate(f)
f.write(FILE_FOOTER)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--stat', type=Path, nargs='+', metavar='PATH[ PATH...]',
help='IntelSEAPI statistics files in CSV format', required=True)
parser.add_argument('--out', type=Path, metavar='cc.h',
help='C++ header file to be generated', required=True)
args = parser.parse_args()
stat = Stat(args.stat)
stat.generate(args.out)
if __name__ == '__main__':
main()