From 8d86da8747d44c135b51b3a052d61422f4bcd1ec Mon Sep 17 00:00:00 2001 From: yejianwu Date: Wed, 3 Jan 2018 14:46:07 +0800 Subject: [PATCH] update codegen template, add distribute lib --- mace/codegen/BUILD | 14 +++ mace/codegen/distribute/use_binary.cc | 35 ++++++ mace/codegen/distribute/use_source.cc | 78 ++++++++++++++ mace/core/runtime/opencl/opencl_runtime.cc | 91 +++------------- mace/core/runtime/opencl/opencl_runtime.h | 1 - mace/mace.bzl | 12 +++ mace/python/tools/binary_codegen.py | 5 +- mace/python/tools/embed_code.cc.tmpl | 111 -------------------- mace/python/tools/encrypt_opencl_codegen.py | 5 +- mace/python/tools/opencl_codegen.py | 5 +- mace/python/tools/str2vec_maps.cc.tmpl | 27 +++++ mace/utils/tuner.h | 2 +- tools/validate_gcn.sh | 10 +- 13 files changed, 194 insertions(+), 202 deletions(-) create mode 100644 mace/codegen/distribute/use_binary.cc create mode 100644 mace/codegen/distribute/use_source.cc delete mode 100644 mace/python/tools/embed_code.cc.tmpl create mode 100644 mace/python/tools/str2vec_maps.cc.tmpl diff --git a/mace/codegen/BUILD b/mace/codegen/BUILD index ad71ff6f..e22741c1 100644 --- a/mace/codegen/BUILD +++ b/mace/codegen/BUILD @@ -5,6 +5,8 @@ package( default_visibility = ["//visibility:public"], ) +load("//mace:mace.bzl", "if_embed_binary_program", "if_use_source_program") + cc_library( name = "generated_models_lib", srcs = glob(["models/*/*.cc"]), @@ -13,12 +15,24 @@ cc_library( deps = [ "//mace/core", "//mace/ops", + "//mace/codegen:distribute_lib", "//mace/codegen:version_lib", "//mace/codegen:generated_opencl_lib", "//mace/codegen:generated_tuning_lib", ], ) +cc_library( + name = "distribute_lib", + srcs = if_embed_binary_program(["distribute/use_binary.cc"]) + + if_use_source_program(["distribute/use_source.cc"]), + copts = ["-std=c++11", "-D_GLIBCXX_USE_C99_MATH_TR1", "-Werror=return-type"], + linkstatic = 1, + deps = [ + "//mace/core", + ], +) + cc_library( name = "generated_opencl_lib", srcs = glob(["opencl/*.cc"]), diff --git a/mace/codegen/distribute/use_binary.cc b/mace/codegen/distribute/use_binary.cc new file mode 100644 index 00000000..de2c8aa3 --- /dev/null +++ b/mace/codegen/distribute/use_binary.cc @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +#include "mace/core/runtime/opencl/cl2_header.h" + +namespace mace { + +bool GetSourceOrBinaryProgram(const std::string &program_name, + const std::string &binary_file_name_prefix, + cl::Context &context, + cl::Device &device, + cl::Program *program, + bool *is_binary) { + extern const std::map> kCompiledProgramMap; + *is_binary = true; + auto it_binary = kCompiledProgramMap.find(binary_file_name_prefix); + if (it_binary == kCompiledProgramMap.end()) { + return false; + } + *program = cl::Program(context, {device}, {it_binary->second}); + return true; +} + +bool GetTuningParams(const char *path, + std::unordered_map> *param_table) { + extern const std::map> kTuningParamsData; + for (auto it = kTuningParamsData.begin(); it != kTuningParamsData.end(); ++it) { + param_table->emplace(it->first, std::vector(it->second.begin(), it->second.end())); + } + return true; +} + +} // namespace mace diff --git a/mace/codegen/distribute/use_source.cc b/mace/codegen/distribute/use_source.cc new file mode 100644 index 00000000..9b2fde0e --- /dev/null +++ b/mace/codegen/distribute/use_source.cc @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include + +#include "mace/core/runtime/opencl/cl2_header.h" + + +namespace mace { + +namespace { +inline void DecryptOpenCLSource(const std::vector &src, + std::vector *dst) { + dst->reserve(src.size()); + + // Keep consistent with encrypt in python tool + const std::string decrypt_lookup_table = "Xiaomi-AI-Platform-Mace"; + size_t lookup_table_size = decrypt_lookup_table.size(); + for (int i = 0; i < src.size(); i++) { + dst->push_back(src[i] ^ decrypt_lookup_table[i % lookup_table_size]); + } +} +} // namespace + +bool GetSourceOrBinaryProgram(const std::string &program_name, + const std::string &binary_file_name_prefix, + cl::Context &context, + cl::Device &device, + cl::Program *program, + bool *is_binary) { + extern const std::map> kEncryptedProgramMap; + *is_binary = false; + auto it_source = kEncryptedProgramMap.find(program_name); + if (it_source == kEncryptedProgramMap.end()) { + return false; + } + cl::Program::Sources sources; + std::vector decrypt_source; + DecryptOpenCLSource(it_source->second, &decrypt_source); + sources.push_back(std::string(decrypt_source.begin(), decrypt_source.end())); + *program = cl::Program(context, sources); + + return true; +} + +bool GetTuningParams(const char *path, + std::unordered_map> *param_table) { + if (path != nullptr) { + std::ifstream ifs(path, std::ios::binary | std::ios::in); + if (ifs.is_open()) { + int32_t key_size = 0; + int32_t params_size = 0; + int32_t params_count = 0; + int64_t num_pramas = 0; + ifs.read(reinterpret_cast(&num_pramas), sizeof(num_pramas)); + while (num_pramas--) { + ifs.read(reinterpret_cast(&key_size), sizeof(key_size)); + std::string key(key_size, ' '); + ifs.read(&key[0], key_size); + + ifs.read(reinterpret_cast(¶ms_size), sizeof(params_size)); + params_count = params_size / sizeof(unsigned int); + std::vector params(params_count); + for (int i = 0; i < params_count; ++i) { + ifs.read(reinterpret_cast(¶ms[i]), sizeof(unsigned int)); + } + param_table->emplace(key, params); + } + ifs.close(); + } else { + return false; + } + } + return true; +} + +} // namespace mace diff --git a/mace/core/runtime/opencl/opencl_runtime.cc b/mace/core/runtime/opencl/opencl_runtime.cc index 51fcd69e..8e761a3e 100644 --- a/mace/core/runtime/opencl/opencl_runtime.cc +++ b/mace/core/runtime/opencl/opencl_runtime.cc @@ -16,47 +16,6 @@ namespace mace { namespace { -bool ReadFile(const std::string &filename, - bool binary, - std::vector *content_ptr) { - MACE_CHECK_NOTNULL(content_ptr); - - std::ios_base::openmode mode = std::ios::in; - if (binary) { - mode |= std::ios::binary; - } - - std::ifstream ifs(filename, mode); - - // Stop eating new lines and whitespace - ifs.unsetf(std::ios::skipws); - - if (!ifs.is_open()) { - LOG(ERROR) << "Failed to open file " << filename; - return false; - } - - ifs.seekg(0, std::ios::end); - const size_t filesize = ifs.tellg(); - if (filesize > 10 * 1024 * 1024) { - LOG(ERROR) << "Filesize overflow 10MB"; - return false; - } - content_ptr->reserve(filesize); - ifs.seekg(0, std::ios::beg); - content_ptr->insert(content_ptr->begin(), std::istreambuf_iterator(ifs), - std::istreambuf_iterator()); - - if (ifs.fail()) { - LOG(ERROR) << "Failed to read from file " << filename; - return false; - } - - ifs.close(); - - return true; -} - bool WriteFile(const std::string &filename, bool binary, const std::vector &content) { @@ -174,23 +133,12 @@ std::string OpenCLRuntime::GenerateCLBinaryFilenamePrefix( return filename_prefix; } -extern bool GetOpenCLProgram( - const std::string &program_name, - const std::string &binary_file_name_prefix, - std::vector *program_vec, - bool *is_opencl_binary); - -const std::vector -OpenCLRuntime::DecryptOpenCLSource(const std::vector &src) { - std::vector res; - res.reserve(src.size()); - std::string decrypt_lookup_table = "Xiaomi-AI-Platform-Mace"; - size_t lookup_table_size = decrypt_lookup_table.size(); - for (int i = 0; i < src.size(); i++) { - res.push_back(src[i] ^ decrypt_lookup_table[i % lookup_table_size]); - } - return res; -} +extern bool GetSourceOrBinaryProgram(const std::string &program_name, + const std::string &binary_file_name_prefix, + cl::Context &context, + cl::Device &device, + cl::Program *program, + bool *is_opencl_binary); void OpenCLRuntime::BuildProgram(const std::string &program_name, const std::string &binary_file_name_prefix, @@ -200,27 +148,18 @@ void OpenCLRuntime::BuildProgram(const std::string &program_name, bool is_opencl_binary = false; std::vector program_vec; - const bool is_success = GetOpenCLProgram(program_name, - binary_file_name_prefix, - &program_vec, - &is_opencl_binary); - MACE_CHECK(is_success, "Failed in GetOpenCLProgram!"); - if (is_opencl_binary) { - *program = cl::Program(this->context(), {device()}, {program_vec}); - VLOG(1) << "Use opencl binaries"; - } else { - cl::Program::Sources sources; - const std::vector decrypt_source = - DecryptOpenCLSource(program_vec); - sources.push_back(std::string(decrypt_source.begin(), decrypt_source.end())); - *program = cl::Program(this->context(), sources); - VLOG(1) << "Use opencl sources"; - } + const bool found = GetSourceOrBinaryProgram(program_name, + binary_file_name_prefix, + context(), + device(), + program, + &is_opencl_binary); + MACE_CHECK(found, "Program not found source: ", program_name, ", or binary: ", + binary_file_name_prefix); // Build program std::string build_options_str = - build_options + " -Werror -cl-mad-enable -cl-fast-relaxed-math -I" + - kernel_path_; + build_options + " -Werror -cl-mad-enable -cl-fast-relaxed-math"; // TODO(heliangliang) -cl-unsafe-math-optimizations -cl-fast-relaxed-math cl_int ret = program->build({device()}, build_options_str.c_str()); if (ret != CL_SUCCESS) { diff --git a/mace/core/runtime/opencl/opencl_runtime.h b/mace/core/runtime/opencl/opencl_runtime.h index 76b6e916..7245b926 100644 --- a/mace/core/runtime/opencl/opencl_runtime.h +++ b/mace/core/runtime/opencl/opencl_runtime.h @@ -55,7 +55,6 @@ class OpenCLRuntime { const std::string &build_options, cl::Program *program); std::string GenerateCLBinaryFilenamePrefix(const std::string &filename_msg); - const std::vector DecryptOpenCLSource(const std::vector &src); private: // All OpenCL object must be a pointer and manually deleted before unloading diff --git a/mace/mace.bzl b/mace/mace.bzl index a6138ee2..6894c710 100644 --- a/mace/mace.bzl +++ b/mace/mace.bzl @@ -30,6 +30,18 @@ def if_profiling_enabled(a): "//conditions:default": [], }) +def if_embed_binary_program(a): + return select({ + "//mace:embed_binary_program": a, + "//conditions:default": [], + }) + +def if_use_source_program(a): + return select({ + "//mace:embed_binary_program": [], + "//conditions:default": a, + }) + def if_enable_neon(a): return select({ "//mace:enable_neon": a, diff --git a/mace/python/tools/binary_codegen.py b/mace/python/tools/binary_codegen.py index 961b7b26..cb1b1280 100644 --- a/mace/python/tools/binary_codegen.py +++ b/mace/python/tools/binary_codegen.py @@ -38,11 +38,10 @@ def generate_cpp_source(): idx += params_size env = jinja2.Environment(loader=jinja2.FileSystemLoader(sys.path[0])) - return env.get_template('embed_code.cc.tmpl').render( + return env.get_template('str2vec_maps.cc.tmpl').render( maps = data_map, data_type = 'unsigned int', - variable_name = FLAGS.variable_name, - mode="tuning_binary" + variable_name = FLAGS.variable_name ) def main(unused_args): diff --git a/mace/python/tools/embed_code.cc.tmpl b/mace/python/tools/embed_code.cc.tmpl deleted file mode 100644 index 04631e2a..00000000 --- a/mace/python/tools/embed_code.cc.tmpl +++ /dev/null @@ -1,111 +0,0 @@ -// -// Copyright (c) 2017 XiaoMi All rights reserved. -// - -// This is a generated file, DO NOT EDIT - -{% if mode == "read_tuning_config" %} -#include -#include -#include -#include - -namespace mace { -bool GetTuningParams(const char *path, - std::unordered_map> *param_table) { - if (path != nullptr) { - std::ifstream ifs(path, std::ios::binary | std::ios::in); - if (ifs.is_open()) { - int32_t key_size = 0; - int32_t params_size = 0; - int32_t params_count = 0; - int64_t num_pramas = 0; - ifs.read(reinterpret_cast(&num_pramas), sizeof(num_pramas)); - while (num_pramas--) { - ifs.read(reinterpret_cast(&key_size), sizeof(key_size)); - std::string key(key_size, ' '); - ifs.read(&key[0], key_size); - - ifs.read(reinterpret_cast(¶ms_size), sizeof(params_size)); - params_count = params_size / sizeof({{data_type}}); - std::vector<{{data_type}}> params(params_count); - for (int i = 0; i < params_count; ++i) { - ifs.read(reinterpret_cast(¶ms[i]), sizeof({{data_type}})); - } - param_table->emplace(key, params); - } - ifs.close(); - } else { - return false; - } - } - return true; -} -} // namespace -{% else %} - -#include -#include -#include -{% if mode == "tuning_binary" %} -#include -{% endif %} - -namespace mace { - -extern const std::map> {{variable_name}}= -{ - {% for key, value in maps.iteritems() %} - { - "{{key}}", - { - {%- for ele in value -%} - {{ele}}, - {%- endfor -%} - } - }, // {{key}} -{% endfor %} -}; - -{% if mode == "cl_encrypt" %} -bool GetOpenCLProgram(const std::string &program_name, - const std::string &binary_file_name_prefix, - std::vector *program_vec, - bool *is_binary) { - *is_binary = false; - auto it_source = {{variable_name}}.find(program_name); - if (it_source == {{variable_name}}.end()) { - return false; - } - *program_vec = it_source->second; - return true; -} - -{% elif mode == "cl_binary" %} -bool GetOpenCLProgram(const std::string &program_name, - const std::string &binary_file_name_prefix, - std::vector *program_vec, - bool *is_binary) { - *is_binary = true; - auto it_source = {{variable_name}}.find(binary_file_name_prefix); - if (it_source == {{variable_name}}.end()) { - return false; - } - *program_vec = it_source->second; - return true; -} - -{% elif mode == "tuning_binary" %} -bool GetTuningParams(const char *path, - std::unordered_map> *param_table) { - for (auto it = kTuningParamsData.begin(); it != kTuningParamsData.end(); ++it) { - param_table->emplace(it->first, std::vector<{{data_type}}>(it->second.begin(), it->second.end())); - } - return true; -} - -{% endif %} - -} // namespace - -{% endif %} diff --git a/mace/python/tools/encrypt_opencl_codegen.py b/mace/python/tools/encrypt_opencl_codegen.py index c5f9fe20..04a4cfc3 100644 --- a/mace/python/tools/encrypt_opencl_codegen.py +++ b/mace/python/tools/encrypt_opencl_codegen.py @@ -45,11 +45,10 @@ def main(unused_args): encrypted_code_maps[file_name[:-3]] = encrypted_code_arr env = jinja2.Environment(loader=jinja2.FileSystemLoader(sys.path[0])) - cpp_cl_encrypted_kernel = env.get_template('embed_code.cc.tmpl').render( + cpp_cl_encrypted_kernel = env.get_template('str2vec_maps.cc.tmpl').render( maps=encrypted_code_maps, data_type='unsigned char', - variable_name='kEncryptedProgramMap', - mode='cl_encrypt') + variable_name='kEncryptedProgramMap') if os.path.isfile(FLAGS.output_path): os.remove(FLAGS.output_path) diff --git a/mace/python/tools/opencl_codegen.py b/mace/python/tools/opencl_codegen.py index 1172172a..a9d73c12 100644 --- a/mace/python/tools/opencl_codegen.py +++ b/mace/python/tools/opencl_codegen.py @@ -27,11 +27,10 @@ def generate_cpp_source(): maps[file_name[:-4]].append(hex(ele)) env = jinja2.Environment(loader=jinja2.FileSystemLoader(sys.path[0])) - return env.get_template('embed_code.cc.tmpl').render( + return env.get_template('str2vec_maps.cc.tmpl').render( maps = maps, data_type = 'unsigned char', - variable_name = 'kCompiledProgramMap', - mode="cl_binary" + variable_name = 'kCompiledProgramMap' ) diff --git a/mace/python/tools/str2vec_maps.cc.tmpl b/mace/python/tools/str2vec_maps.cc.tmpl new file mode 100644 index 00000000..354af0aa --- /dev/null +++ b/mace/python/tools/str2vec_maps.cc.tmpl @@ -0,0 +1,27 @@ +// +// Copyright (c) 2017 XiaoMi All rights reserved. +// + +// This is a generated file, DO NOT EDIT + +#include +#include +#include + +namespace mace { + +extern const std::map> {{variable_name}}= +{ + {% for key, value in maps.iteritems() %} + { + "{{key}}", + { + {%- for ele in value -%} + {{ele}}, + {%- endfor -%} + } + }, // {{key}} +{% endfor %} +}; + +} // namespace diff --git a/mace/utils/tuner.h b/mace/utils/tuner.h index 50a53b18..9404a565 100644 --- a/mace/utils/tuner.h +++ b/mace/utils/tuner.h @@ -104,7 +104,7 @@ class Tuner { inline void ReadRunParamters() { bool success = GetTuningParams(path_, ¶m_table_); if (!success) { - LOG(WARNING) << "Read run parameter failed."; + LOG(WARNING) << "Get run parameter failed."; } } diff --git a/tools/validate_gcn.sh b/tools/validate_gcn.sh index 14590c09..b3ed6006 100644 --- a/tools/validate_gcn.sh +++ b/tools/validate_gcn.sh @@ -35,6 +35,9 @@ VERSION_SOURCE_PATH=${CODEGEN_DIR}/version build_and_run() { EMBED_OPENCL_BINARY=$1 + if [ "$EMBED_OPENCL_BINARY" = true ]; then + EMBED_OPENCL_BINARY_BUILD_FLAGS="--define embed_binary_program=true" + fi bazel build -c opt --strip always mace/examples:mace_run \ --crosstool_top=//external:android/crosstool \ @@ -44,6 +47,9 @@ build_and_run() --copt=-DMACE_MODEL_FUNCTION=Create${MODEL_TAG} adb shell "mkdir -p ${PHONE_DATA_DIR}" + if [ "$EMBED_OPENCL_BINARY" = false ]; then + adb shell "mkdir -p ${KERNEL_DIR}" + fi adb push ${MODEL_DIR}/${INPUT_FILE_NAME} ${PHONE_DATA_DIR} adb push bazel-bin/mace/examples/mace_run ${PHONE_DATA_DIR} @@ -99,13 +105,9 @@ bash mace/tools/git/gen_version_source.sh ${VERSION_SOURCE_PATH}/version.cc echo "Step 4: Generate encrypted opencl source and read tuning method" rm -rf ${CL_CODEGEN_DIR} -rm -rf ${TUNING_CODEGEN_DIR} mkdir -p ${CL_CODEGEN_DIR} -mkdir -p ${TUNING_CODEGEN_DIR} python mace/python/tools/encrypt_opencl_codegen.py \ --cl_kernel_dir=./mace/kernels/opencl/cl/ --output_path=${CL_CODEGEN_DIR}/opencl_encrypt_program.cc -python mace/python/tools/read_tuning_codegen.py \ - --output_path=${TUNING_CODEGEN_DIR}/read_tuning_params.cc echo "Step 5: Run model on the phone with files" build_and_run false -- GitLab