From 92c1822942dfb2dbd5c27b197a8b4b1514772178 Mon Sep 17 00:00:00 2001 From: yeyunpeng Date: Wed, 18 Nov 2020 10:07:34 +0800 Subject: [PATCH] add cropper --- cmake/package_lite.cmake | 18 +- mindspore/lite/CMakeLists.txt | 1 + .../lite/tools/lib_cropper/CMakeLists.txt | 20 ++ .../tools/lib_cropper/build_cropper_config.sh | 170 +++++++++++ .../lite/tools/lib_cropper/cropper_flags.cc | 105 +++++++ .../lite/tools/lib_cropper/cropper_flags.h | 45 +++ .../lite/tools/lib_cropper/cropper_utils.cc | 53 ++++ .../lite/tools/lib_cropper/cropper_utils.h | 28 ++ .../lite/tools/lib_cropper/lib_cropper.cc | 276 ++++++++++++++++++ .../lite/tools/lib_cropper/lib_cropper.h | 68 +++++ mindspore/lite/tools/lib_cropper/main.cc | 23 ++ 11 files changed, 799 insertions(+), 8 deletions(-) create mode 100644 mindspore/lite/tools/lib_cropper/CMakeLists.txt create mode 100644 mindspore/lite/tools/lib_cropper/build_cropper_config.sh create mode 100644 mindspore/lite/tools/lib_cropper/cropper_flags.cc create mode 100644 mindspore/lite/tools/lib_cropper/cropper_flags.h create mode 100644 mindspore/lite/tools/lib_cropper/cropper_utils.cc create mode 100644 mindspore/lite/tools/lib_cropper/cropper_utils.h create mode 100644 mindspore/lite/tools/lib_cropper/lib_cropper.cc create mode 100644 mindspore/lite/tools/lib_cropper/lib_cropper.h create mode 100644 mindspore/lite/tools/lib_cropper/main.cc diff --git a/cmake/package_lite.cmake b/cmake/package_lite.cmake index d1eb6f9fdb..431e373c2b 100644 --- a/cmake/package_lite.cmake +++ b/cmake/package_lite.cmake @@ -55,7 +55,7 @@ if (BUILD_MINDDATA STREQUAL "lite") endif () if (BUILD_MINDDATA STREQUAL "lite_cv") - if (PLATFORM_ARM64) + if (PLATFORM_ARM64) install(DIRECTORY ${TOP_DIR}/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv DESTINATION ${MIND_DATA_INC_DIR} COMPONENT ${COMPONENT_NAME} FILES_MATCHING PATTERN "*.h") install(FILES ${TOP_DIR}/mindspore/lite/build/minddata/libminddata-lite.so DESTINATION ${MIND_DATA_LIB_DIR} COMPONENT ${COMPONENT_NAME}) elseif (PLATFORM_ARM32) @@ -81,7 +81,7 @@ if (PLATFORM_ARM64) install(DIRECTORY ${flatbuffers_INC} DESTINATION ${FLATBF_DIR} COMPONENT ${COMPONENT_NAME}) if (ENABLE_TOOLS) install(TARGETS benchmark RUNTIME DESTINATION ${MAIN_DIR}-${COMPONENT_NAME}/benchmark COMPONENT ${COMPONENT_NAME}) - endif() + endif () elseif (PLATFORM_ARM32) if (SUPPORT_TRAIN) install(DIRECTORY ${TOP_DIR}/mindspore/lite/include/ DESTINATION ${INC_DIR} COMPONENT ${COMPONENT_NAME} FILES_MATCHING PATTERN "*.h") @@ -96,7 +96,7 @@ elseif (PLATFORM_ARM32) install(DIRECTORY ${flatbuffers_INC} DESTINATION ${FLATBF_DIR} COMPONENT ${COMPONENT_NAME}) if (ENABLE_TOOLS) install(TARGETS benchmark RUNTIME DESTINATION ${MAIN_DIR}-${COMPONENT_NAME}/benchmark COMPONENT ${COMPONENT_NAME}) - endif() + endif () elseif (WIN32) get_filename_component(CXX_DIR ${CMAKE_CXX_COMPILER} PATH) file(GLOB LIB_LIST ${CXX_DIR}/libstdc++-6.dll ${CXX_DIR}/libwinpthread-1.dll ${CXX_DIR}/libssp-0.dll ${CXX_DIR}/libgcc_s_seh-1.dll) @@ -104,7 +104,7 @@ elseif (WIN32) install(TARGETS converter_lite RUNTIME DESTINATION ${MAIN_DIR}-${COMPONENT_NAME}/converter COMPONENT ${COMPONENT_NAME}) install(FILES ${LIB_LIST} DESTINATION ${MAIN_DIR}-${COMPONENT_NAME}/converter COMPONENT ${COMPONENT_NAME}) install(FILES ${TOP_DIR}/build/mindspore/tools/converter/mindspore_core/gvar/libmindspore_gvar.dll DESTINATION ${MAIN_DIR}-${COMPONENT_NAME}/converter COMPONENT ${COMPONENT_NAME}) - install(FILES ${glog_LIBPATH}/../bin/libglog.dll DESTINATION ${MAIN_DIR}-${COMPONENT_NAME}/converter COMPONENT ${COMPONENT_NAME}) + install(FILES ${glog_LIBPATH}/../bin/libglog.dll DESTINATION ${MAIN_DIR}-${COMPONENT_NAME}/converter COMPONENT ${COMPONENT_NAME}) endif () if (ENABLE_TOOLS) install(TARGETS benchmark RUNTIME DESTINATION ${MAIN_DIR}-${WIN_RUN_X86_NAME}/benchmark COMPONENT ${WIN_RUN_X86_NAME}) @@ -123,7 +123,7 @@ elseif (WIN32) install(FILES ${TOP_DIR}/build/mindspore/src/libmindspore-lite.a DESTINATION ${WIN_LIB_DIR_RUN_X86} COMPONENT ${WIN_RUN_X86_NAME}) install(FILES ${TOP_DIR}/build/mindspore/src/libmindspore-lite.dll.a DESTINATION ${WIN_LIB_DIR_RUN_X86} COMPONENT ${WIN_RUN_X86_NAME}) install(FILES ${TOP_DIR}/build/mindspore/src/libmindspore-lite.dll DESTINATION ${WIN_LIB_DIR_RUN_X86} COMPONENT ${WIN_RUN_X86_NAME}) - endif() + endif () else () if (SUPPORT_TRAIN) install(DIRECTORY ${TOP_DIR}/mindspore/lite/include/ DESTINATION ${INC_DIR_RUN_X86} COMPONENT ${RUN_X86_COMPONENT_NAME} FILES_MATCHING PATTERN "*.h") @@ -140,10 +140,12 @@ else () install(TARGETS converter_lite RUNTIME DESTINATION ${MAIN_DIR}-${COMPONENT_NAME}/converter COMPONENT ${COMPONENT_NAME}) install(FILES ${TOP_DIR}/mindspore/lite/build/tools/converter/mindspore_core/gvar/libmindspore_gvar.so DESTINATION ${MAIN_DIR}-${COMPONENT_NAME}/lib COMPONENT ${COMPONENT_NAME}) install(FILES ${glog_LIBPATH}/libglog.so.0.4.0 DESTINATION ${MAIN_DIR}-${COMPONENT_NAME}/third_party/glog/lib RENAME libglog.so.0 COMPONENT ${COMPONENT_NAME}) - endif() + endif () if (ENABLE_TOOLS) install(TARGETS benchmark RUNTIME DESTINATION ${MAIN_DIR}-${RUN_X86_COMPONENT_NAME}/benchmark COMPONENT ${RUN_X86_COMPONENT_NAME}) - endif() + install(TARGETS lib_cropper RUNTIME DESTINATION ${MAIN_DIR}-${RUN_X86_COMPONENT_NAME}/lib_cropper COMPONENT ${RUN_X86_COMPONENT_NAME}) + install(FILES ${TOP_DIR}/mindspore/lite/build/tools/lib_cropper/cropper_mapping_cpu.cfg DESTINATION ${MAIN_DIR}-${RUN_X86_COMPONENT_NAME}/lib_cropper COMPONENT ${RUN_X86_COMPONENT_NAME}) + endif () endif () if (CMAKE_SYSTEM_NAME MATCHES "Windows") @@ -164,6 +166,6 @@ if (WIN32) set(CPACK_PACKAGE_DIRECTORY ${TOP_DIR}/output) else () set(CPACK_PACKAGE_DIRECTORY ${TOP_DIR}/output/tmp) -endif() +endif () set(CPACK_PACKAGE_CHECKSUM SHA256) include(CPack) diff --git a/mindspore/lite/CMakeLists.txt b/mindspore/lite/CMakeLists.txt index 62b533ba21..e33d2b0ce1 100644 --- a/mindspore/lite/CMakeLists.txt +++ b/mindspore/lite/CMakeLists.txt @@ -224,6 +224,7 @@ if (NOT WIN32) if (ENABLE_TOOLS) if (NOT PLATFORM_ARM32 AND NOT PLATFORM_ARM64) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tools/schema_gen) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tools/lib_cropper) endif () endif() if (BUILD_TESTCASES) diff --git a/mindspore/lite/tools/lib_cropper/CMakeLists.txt b/mindspore/lite/tools/lib_cropper/CMakeLists.txt new file mode 100644 index 0000000000..cd34b0c82c --- /dev/null +++ b/mindspore/lite/tools/lib_cropper/CMakeLists.txt @@ -0,0 +1,20 @@ +# add shared link library +set(COMMON_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/../common/flag_parser.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../src/common/file_utils.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../../src/common/utils.cc + ) + +add_executable(lib_cropper + ${CMAKE_CURRENT_SOURCE_DIR}/main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/lib_cropper.cc + ${CMAKE_CURRENT_SOURCE_DIR}/cropper_flags.cc + ${CMAKE_CURRENT_SOURCE_DIR}/cropper_utils.cc + ${COMMON_SRC}) + +add_dependencies(lib_cropper fbs_src) + +target_link_libraries(lib_cropper mindspore-lite_static) + +add_custom_command(TARGET lib_cropper POST_BUILD COMMAND + bash build_cropper_config.sh WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/mindspore/lite/tools/lib_cropper/build_cropper_config.sh b/mindspore/lite/tools/lib_cropper/build_cropper_config.sh new file mode 100644 index 0000000000..4c7f18994b --- /dev/null +++ b/mindspore/lite/tools/lib_cropper/build_cropper_config.sh @@ -0,0 +1,170 @@ +#!/bin/bash + +CURRENT_PATH=$(pwd) +MINDSPORE_HOME="${CURRENT_PATH}/../../../.." +echo "MINDSPORE_HOME path is ${MINDSPORE_HOME}" +CROPPER_OUTPUT_DIR=${MINDSPORE_HOME}/mindspore/lite/build/tools/lib_cropper +mkdir -p ${CROPPER_OUTPUT_DIR} +MAPPING_OUTPUT_FILE_NAME_TMP=${CROPPER_OUTPUT_DIR}/cropper_mapping_cpu_tmp.cfg +MAPPING_OUTPUT_FILE_NAME=${CROPPER_OUTPUT_DIR}/cropper_mapping_cpu.cfg +echo "MAPPING_OUTPUT_FILE_NAME is ${MAPPING_OUTPUT_FILE_NAME}" +[ -n "${MAPPING_OUTPUT_FILE_NAME_TMP}" ] && rm -f ${MAPPING_OUTPUT_FILE_NAME_TMP} +[ -n "${MAPPING_OUTPUT_FILE_NAME}" ] && rm -f ${MAPPING_OUTPUT_FILE_NAME} +ops_list=() +DEFINE_STR="-DENABLE_ANDROID -DENABLE_ARM -DENABLE_ARM64 -DENABLE_NEON -DNO_DLIB -DUSE_ANDROID_LOG -DANDROID" +# get the flatbuffers path +if [ ${MSLIBS_CACHE_PATH} ]; then + FLATBUFFERS_LIST=($(ls -d ${MSLIBS_CACHE_PATH}/flatbuffers_*/include)) + FLATBUFFERS=${FLATBUFFERS_LIST[0]} + echo "FLATBUFFERS path is ${FLATBUFFERS}" +else + FLATBUFFERS=$(ls -d ${MINDSPORE_HOME}/mindspore/lite/build/.mslib/flatbuffers_*/include) + echo "FLATBUFFERS path is ${FLATBUFFERS}" +fi + +HEADER_LOCATION="-I${MINDSPORE_HOME} +-I${MINDSPORE_HOME}/mindspore/core +-I${MINDSPORE_HOME}/mindspore/core/ir +-I${MINDSPORE_HOME}/mindspore/ccsrc +-I${MINDSPORE_HOME}/mindspore/lite +-I${MINDSPORE_HOME}/mindspore/lite/src/runtime/kernel/arm +-I${MINDSPORE_HOME}/third_party +-I${MINDSPORE_HOME}/mindspore/lite/build +-I${MINDSPORE_HOME}/cmake/../third_party/securec/include +-I${FLATBUFFERS} +-I${MINDSPORE_HOME}/mindspore/lite/build/schema +-I${MINDSPORE_HOME}/mindspore/lite/build/schema/inner +-I${MINDSPORE_HOME}/mindspore/lite/src/../nnacl +-I${MINDSPORE_HOME}/mindspore/lite/src/../nnacl/optimize" + +REMOVE_LISTS_STR="" +getDeep() { + map_files=$(gcc -MM ${2} ${DEFINE_STR} ${HEADER_LOCATION}) + # first is *.o second is *.cc + array_deep=($(echo ${map_files} | awk -F '\' '{for(i=3;i<=NF;i++){print $i}}' | grep -E 'src/runtime|nnacl' | egrep -v ${REMOVE_LISTS_STR})) + for array_deep_file in ${array_deep[@]}; do + # only add existing files + if [[ -e ${array_deep_file%h*}cc ]]; then + file_split=$(echo ${array_deep_file} | awk -F '/' '{print $NF}') + echo "${1},${3},${file_split%h*}cc.o" >>${MAPPING_OUTPUT_FILE_NAME_TMP} + fi + if [[ -e ${array_deep_file%h*}c ]]; then + file_split=$(echo ${array_deep_file} | awk -F '/' '{print $NF}') + echo "${1},${3},${file_split%h*}c.o" >>${MAPPING_OUTPUT_FILE_NAME_TMP} + fi + done +} +getOpsFile() { + echo "start get operator mapping file $3" + for type in ${ops_list[@]}; do + # get mapping + ret=$(egrep -r -l "$1${type}," $2) + array=(${ret}) + for file in ${array[@]}; do + # delete \n + out_file=$(echo ${file} | awk -F '/' '{print $NF}') + # concat schemaType + fileType + fileName append to files + echo "${type},${3},${out_file}.o" >>${MAPPING_OUTPUT_FILE_NAME_TMP} + map_files=$(gcc -MM ${file} ${DEFINE_STR} ${HEADER_LOCATION}) + # first is *.o second is *.cc + array_file=($(echo ${map_files} | awk -F '\' '{for(i=3;i<=NF;i++){print $i}}' | grep -E 'src/runtime|nnacl' | egrep -v ${REMOVE_LISTS_STR})) + for array_file in ${array_file[@]}; do + # only add existing files + if [[ -e ${array_file%h*}cc ]]; then + getDeep ${type} ${array_file%h*}cc ${3} & + array_file_split=$(echo ${array_file} | awk -F '/' '{print $NF}') + echo "${type},${3},${array_file_split%h*}cc.o" >>${MAPPING_OUTPUT_FILE_NAME_TMP} + fi + if [[ -e ${array_file%h*}c ]]; then + getDeep ${type} ${array_file%h*}c ${3} & + array_file_split=$(echo ${array_file} | awk -F '/' '{print $NF}') + echo "${type},${3},${array_file_split%h*}c.o" >>${MAPPING_OUTPUT_FILE_NAME_TMP} + fi + done + done + done +} +getCommonFile() { + echo "start get common files" + include_h=($(ls ${MINDSPORE_HOME}/mindspore/lite/include/*.h)) + src_files_h=($(ls ${MINDSPORE_HOME}/mindspore/lite/src/*.h)) + common_files_h=($(ls ${MINDSPORE_HOME}/mindspore/lite/src/common/*.h)) + runtime_files_h=($(ls ${MINDSPORE_HOME}/mindspore/lite/src/runtime/*.h)) + others_files=( + ${MINDSPORE_HOME}/mindspore/lite/src/populate/populate_register.h + ${MINDSPORE_HOME}/mindspore/lite/src/ops/primitive_c.h + ${MINDSPORE_HOME}/mindspore/lite/nnacl/nnacl_utils.h + ${MINDSPORE_HOME}/mindspore/lite/nnacl/pack.h + ${MINDSPORE_HOME}/mindspore/lite/src/runtime/kernel/arm/fp16/common_fp16.h + ) + all_files_h=(${include_h[@]} ${src_files_h[@]} ${common_files_h[@]} ${runtime_files_h[@]} ${others_files[@]}) + + # concat regx + REMOVE_LISTS_STR="${all_files_h[0]}" + for val in ${all_files_h[@]:1}; do + REMOVE_LISTS_STR="$REMOVE_LISTS_STR|$val" + done + + src_files=($(ls ${MINDSPORE_HOME}/mindspore/lite/src/*.cc)) + common_files=($(ls ${MINDSPORE_HOME}/mindspore/lite/src/common/*.cc)) + runtime_files_cc=($(ls ${MINDSPORE_HOME}/mindspore/lite/src/runtime/*.cc)) + runtime_files_c=($(ls ${MINDSPORE_HOME}/mindspore/lite/src/runtime/*.c)) + + # sava all assembly files + assembly_files=("$(ls ${MINDSPORE_HOME}/mindspore/lite/nnacl/assembly/*/*.S)") + others_files=( + ${MINDSPORE_HOME}/mindspore/lite/src/ops/primitive_c.cc + ${MINDSPORE_HOME}/mindspore/lite/nnacl/nnacl_utils.c + ${MINDSPORE_HOME}/mindspore/lite/nnacl/pack.c + ${MINDSPORE_HOME}/mindspore/lite/src/runtime/kernel/arm/fp16/common_fp16.cc + ${MINDSPORE_HOME}/mindspore/lite/src/ops/populate/arithmetic_populate.cc + ${MINDSPORE_HOME}/mindspore/lite/src/ops/populate/arithmetic_self_populate.cc + ) + all_files=(${src_files[@]} ${common_files[@]} ${runtime_files_cc[@]} ${runtime_files_c[@]} ${others_files[@]} ${assembly_files[@]}) + + for file in ${all_files[@]}; do + map_files=$(gcc -MM ${file} ${DEFINE_STR} ${HEADER_LOCATION}) + # first is *.o second is *.cc + array_runtime=($(echo ${map_files} | awk -F '\' '{for(i=3;i<=NF;i++){print $i}}' | grep -v "flatbuffers" | egrep -v ${REMOVE_LISTS_STR})) + # only add existing files + for array_runtime_file in "${array_runtime[@]}"; do + if [[ -e ${array_runtime_file%h*}cc && ! ${all_files[*]} =~ ${array_runtime_file%h*}cc ]]; then + all_files=("${all_files[@]}" "${array_runtime_file%h*}cc") + fi + if [[ -e ${array_runtime_file%h*}c && ! ${all_files[*]} =~ ${array_runtime_file%h*}c ]]; then + all_files=("${all_files[@]}" "${array_runtime_file%h*}c") + fi + done + done + for file in ${all_files[@]}; do + file=$(echo ${file} | awk -F '/' '{print $NF}') + echo "CommonFile,common,${file}.o" >>${MAPPING_OUTPUT_FILE_NAME_TMP} & + done + wait +} + +# automatically generate operator list +generateOpsList() { + echo "start generate operator list" + ops=($(egrep "PrimitiveType_.* = " "${MINDSPORE_HOME}/mindspore/lite/build/schema/model_generated.h" | awk -F '_' '{print $2}' | awk -F ' ' '{print $1}')) + + ops_num=$((${#ops[@]} - 3)) + echo "ops nums:${ops_num}" + ops_list=${ops[@]:1:$ops_num} +} +echo "Start getting all file associations." +generateOpsList +getCommonFile +# get src/ops +getOpsFile "Registry\(schema::PrimitiveType_" "${MINDSPORE_HOME}/mindspore/lite/src/ops" "prototype" & +getOpsFile "REG_KERNEL\(.*?, kNumberTypeFloat32, PrimitiveType_" "${MINDSPORE_HOME}/mindspore/lite/src/runtime/kernel/arm" "kNumberTypeFloat32" & +getOpsFile "REG_KERNEL\(.*?, kNumberTypeFloat16, PrimitiveType_" "${MINDSPORE_HOME}/mindspore/lite/src/runtime/kernel/arm" "kNumberTypeFloat16" & +getOpsFile "REG_KERNEL\(.*?, kNumberTypeInt8, PrimitiveType_" "${MINDSPORE_HOME}/mindspore/lite/src/runtime/kernel/arm" "kNumberTypeInt8" & +wait +echo "remove duplicate files" +# remove duplicate files +sort ${MAPPING_OUTPUT_FILE_NAME_TMP} | uniq >${MAPPING_OUTPUT_FILE_NAME} +# modify file permissions to read-only +[ -n "${MAPPING_OUTPUT_FILE_NAME_TMP}" ] && rm -f ${MAPPING_OUTPUT_FILE_NAME_TMP} +chmod 444 ${MAPPING_OUTPUT_FILE_NAME} +echo "Complete all tasks." diff --git a/mindspore/lite/tools/lib_cropper/cropper_flags.cc b/mindspore/lite/tools/lib_cropper/cropper_flags.cc new file mode 100644 index 0000000000..076e2abadf --- /dev/null +++ b/mindspore/lite/tools/lib_cropper/cropper_flags.cc @@ -0,0 +1,105 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * 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. + */ + +#include "tools/lib_cropper/cropper_flags.h" +#include +#include "tools/lib_cropper/cropper_utils.h" +#include "src/common/file_utils.h" + +namespace mindspore { +namespace lite { +namespace cropper { +CropperFlags::CropperFlags() { + AddFlag(&CropperFlags::package_file_, "packageFile", "The libmindspore-lite.a file that needs to be cropped", ""); + AddFlag(&CropperFlags::model_file_, "modelFile", "List of model files, separated by commas", ""); + AddFlag(&CropperFlags::model_folder_path_, "modelFolderPath", "Load all ms models in the folder", ""); + AddFlag(&CropperFlags::config_file_, "configFile", "The mapping configuration file path", ""); + AddFlag(&CropperFlags::output_file_, "outputFile", "Output library file path", ""); +} + +int CropperFlags::Init(int argc, const char **argv) { + if (argc == 1) { + std::cout << this->Usage() << std::endl; + return RET_SUCCESS_EXIT; + } + Option err = this->ParseFlags(argc, argv); + + if (err.IsSome()) { + std::cerr << err.Get(); + std::cerr << this->Usage() << std::endl; + return RET_INPUT_PARAM_INVALID; + } + + if (this->help) { + std::cout << this->Usage() << std::endl; + return RET_SUCCESS_EXIT; + } + + MS_LOG(INFO) << "packageFile = " << this->package_file_; + MS_LOG(INFO) << "modelFile = " << this->model_file_; + MS_LOG(INFO) << "modelFolderPath = " << this->model_folder_path_; + MS_LOG(INFO) << "configFile = " << this->config_file_; + MS_LOG(INFO) << "outputFile = " << this->output_file_; + + if (this->package_file_.empty()) { + std::cerr << "INPUT MISSING: packageFile is necessary" << std::endl; + return RET_INPUT_PARAM_INVALID; + } else { + // Verify whether it is a static library file(.a) + if (ValidFileSuffix(this->package_file_, "a") != RET_OK) { + return RET_INPUT_PARAM_INVALID; + } + this->package_file_ = RealPath(this->package_file_.c_str()); + if (this->package_file_.empty()) { + return RET_INPUT_PARAM_INVALID; + } + } + + if (this->model_file_.empty() && this->model_folder_path_.empty()) { + std::cerr << "INPUT MISSING: modelFile or modelFolderPath is necessary" << std::endl; + return RET_INPUT_PARAM_INVALID; + } else if (!this->model_file_.empty() && !this->model_folder_path_.empty()) { + std::cerr << "INPUT MISSING: modelFile and modelFolderPath must choose one" << std::endl; + return RET_INPUT_PARAM_INVALID; + } else if (!this->model_folder_path_.empty()) { + this->model_folder_path_ = RealPath(this->model_folder_path_.c_str()); + if (this->model_folder_path_.empty()) { + return RET_INPUT_PARAM_INVALID; + } + } + + if (this->config_file_.empty()) { + std::cerr << "INPUT MISSING: configFile is necessary" << std::endl; + return RET_INPUT_PARAM_INVALID; + } + this->config_file_ = RealPath(this->config_file_.c_str()); + if (this->config_file_.empty()) { + return RET_INPUT_PARAM_INVALID; + } + + if (this->output_file_.empty()) { + this->output_file_ = this->package_file_; + } + this->output_file_ = RealPath(this->output_file_.c_str()); + if (this->output_file_.empty()) { + return RET_INPUT_PARAM_INVALID; + } + return RET_OK; +} + +} // namespace cropper +} // namespace lite +} // namespace mindspore diff --git a/mindspore/lite/tools/lib_cropper/cropper_flags.h b/mindspore/lite/tools/lib_cropper/cropper_flags.h new file mode 100644 index 0000000000..273bd5c99d --- /dev/null +++ b/mindspore/lite/tools/lib_cropper/cropper_flags.h @@ -0,0 +1,45 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * 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. + */ + +#ifndef MINDSPORE_LITE_TOOLS_LIB_CROPPER_LIB_CROPPER_FLAGS_H +#define MINDSPORE_LITE_TOOLS_LIB_CROPPER_LIB_CROPPER_FLAGS_H + +#include +#include "tools/common/flag_parser.h" +#include "ir/dtype/type_id.h" + +namespace mindspore { +namespace lite { +namespace cropper { + +class CropperFlags : public virtual mindspore::lite::FlagParser { + public: + CropperFlags(); + ~CropperFlags() override = default; + int Init(int argc, const char **argv); + + public: + std::string package_file_; + std::string model_file_; + std::string model_folder_path_; + std::string config_file_; + std::string output_file_; +}; +} // namespace cropper +} // namespace lite +} // namespace mindspore + +#endif diff --git a/mindspore/lite/tools/lib_cropper/cropper_utils.cc b/mindspore/lite/tools/lib_cropper/cropper_utils.cc new file mode 100644 index 0000000000..b150dd2e5a --- /dev/null +++ b/mindspore/lite/tools/lib_cropper/cropper_utils.cc @@ -0,0 +1,53 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * 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. + */ + +#include "tools/lib_cropper/cropper_utils.h" +#include +#include +#include "src/common/log_adapter.h" +#include "include/errorcode.h" + +namespace mindspore { +namespace lite { +namespace cropper { +int ValidFileSuffix(const std::string &filename, const std::string &suffix) { + std::string suffixStr = filename.substr(filename.find_last_of('.') + 1); + if (suffix == suffixStr) { + return RET_OK; + } else { + MS_LOG(ERROR) << "The file name suffix needs: " << suffix << ", but file is " << filename; + return RET_ERROR; + } +} +int ValidFile(std::ifstream &in_file, const char *file_path) { + if (!in_file.good()) { + std::cerr << "file: " << file_path << " is not exist" << std::endl; + MS_LOG(ERROR) << "file: " << file_path << " is not exist"; + return RET_ERROR; + } + + if (!in_file.is_open()) { + std::cerr << "file: " << file_path << " open failed" << std::endl; + MS_LOG(ERROR) << "file: " << file_path << " open failed"; + in_file.close(); + return RET_ERROR; + } + return RET_OK; +} + +} // namespace cropper +} // namespace lite +} // namespace mindspore diff --git a/mindspore/lite/tools/lib_cropper/cropper_utils.h b/mindspore/lite/tools/lib_cropper/cropper_utils.h new file mode 100644 index 0000000000..8161a70c3c --- /dev/null +++ b/mindspore/lite/tools/lib_cropper/cropper_utils.h @@ -0,0 +1,28 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * 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. + */ + +#ifndef MINDSPORE_LITE_TOOLS_LIB_CROPPER_LIB_CROPPER_UTILS_H +#define MINDSPORE_LITE_TOOLS_LIB_CROPPER_LIB_CROPPER_UTILS_H +#include +namespace mindspore { +namespace lite { +namespace cropper { +int ValidFileSuffix(const std::string &filename, const std::string &suffix); +int ValidFile(std::ifstream &in_file, const char *file_path); +} // namespace cropper +} // namespace lite +} // namespace mindspore +#endif // MINDSPORE_LITE_TOOLS_CROPPER_CROPPER_UTILS_H diff --git a/mindspore/lite/tools/lib_cropper/lib_cropper.cc b/mindspore/lite/tools/lib_cropper/lib_cropper.cc new file mode 100644 index 0000000000..3f8788f0c7 --- /dev/null +++ b/mindspore/lite/tools/lib_cropper/lib_cropper.cc @@ -0,0 +1,276 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * 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. + */ + +#include +#include +#include "tools/lib_cropper/lib_cropper.h" +#include "tools/lib_cropper/cropper_utils.h" +#define BUF_SIZE 1024 + +namespace mindspore { +namespace lite { +namespace cropper { +static const char *DELIM_COMMA = ","; + +int Cropper::ReadPackage() { + std::ifstream in_file(this->flags_->package_file_); + if (ValidFile(in_file, this->flags_->package_file_.c_str()) == RET_OK) { + in_file.close(); + + char buf[BUF_SIZE]; + String cmd = "ar -t " + this->flags_->package_file_; + MS_LOG(DEBUG) << cmd; + + FILE *p_file = popen(cmd.c_str(), "r"); + if (!p_file) { + MS_LOG(ERROR) << "Error to popen" << this->flags_->package_file_; + return RET_ERROR; + } + while (fgets(buf, BUF_SIZE, p_file) != nullptr) { + this->all_files_.push_back(String(buf).substr(0, String(buf).length() - 1)); + this->discard_files_.push_back(String(buf).substr(0, String(buf).length() - 1)); + } + pclose(p_file); + MS_LOG(DEBUG) << "file nums: " << this->all_files_.size(); + } else { + return RET_ERROR; + } + return RET_OK; +} + +int Cropper::RunCropper() { + int status; + status = ReadPackage(); + if (status != RET_OK) { + MS_LOG(ERROR) << "read package failed."; + return status; + } + status = GetModelFiles(); + if (status != RET_OK) { + MS_LOG(ERROR) << "get model files failed."; + return status; + } + status = GetModelOps(); + if (status != RET_OK) { + MS_LOG(ERROR) << "get model ops failed."; + return status; + } + status = GetOpMatchFiles(); + if (status != RET_OK) { + MS_LOG(ERROR) << "get op match files failed."; + return status; + } + status = GetDiscardFileList(); + if (status != RET_OK) { + MS_LOG(ERROR) << "get discard file list failed."; + return status; + } + status = CutPackage(); + if (status != RET_OK) { + MS_LOG(ERROR) << "cut package failed."; + return status; + } + return RET_OK; +} +int Cropper::GetModelOps() { + for (const auto &path : this->model_files_) { + auto context = std::make_shared(); + size_t buffer_lens; + char *graph_buf = ReadFile(path.c_str(), &buffer_lens); + if (graph_buf == nullptr) { + MS_LOG(ERROR) << "Read model file failed while running " << path.c_str(); + std::cerr << "Read model file failed while running " << path.c_str() << std::endl; + return RET_ERROR; + } + auto meta_graph = schema::GetMetaGraph(graph_buf); + if (meta_graph == nullptr) { + delete[] graph_buf; + MS_LOG(ERROR) << "meta_graph is nullptr!"; + std::cerr << "meta_graph is nullptr!" << std::endl; + return RET_ERROR; + } + auto nodes = meta_graph->nodes(); + for (auto node : *nodes) { + this->all_operators_.insert(node->primitive()->value_type()); + MS_LOG(DEBUG) << "PrimitiveType:" << schema::EnumNamePrimitiveType(node->primitive()->value_type()) + << " QuantType:" << schema::EnumNameQuantType(node->quantType()); + // QuantType_AwareTraining may change + if (node->quantType() == schema::QuantType_AwareTraining || node->quantType() == schema::QuantType_PostTraining) { + this->int8_operators_.insert(node->primitive()->value_type()); + } else { + this->fp32_operators_.insert(node->primitive()->value_type()); + } + } + delete[] graph_buf; + } + return RET_OK; +} +int Cropper::GetModelFiles() { + if (!this->flags_->model_file_.empty()) { + auto files = StringSplit(this->flags_->model_file_, std::string(DELIM_COMMA)); + for (const auto &file : files) { + if (ValidFileSuffix(file, "ms") != RET_OK) { + return RET_INPUT_PARAM_INVALID; + } + MS_LOG(DEBUG) << file; + String realPath = RealPath(file.c_str()); + if (realPath.empty()) { + return RET_INPUT_PARAM_INVALID; + } + this->model_files_.push_back(realPath); + } + } + // get models from folder + if (!this->flags_->model_folder_path_.empty()) { + String cmd = "ls " + this->flags_->model_folder_path_ + "/*.ms"; + MS_LOG(DEBUG) << cmd; + + char buf[BUF_SIZE]; + FILE *p_file = popen(cmd.c_str(), "r"); + if (!p_file) { + MS_LOG(ERROR) << "Error to popen"; + return RET_ERROR; + } + while (fgets(buf, BUF_SIZE, p_file) != nullptr) { + String realPath = RealPath(String(buf).substr(0, String(buf).length() - 1).c_str()); + if (realPath.empty()) { + return RET_INPUT_PARAM_INVALID; + } + this->model_files_.emplace_back(realPath); + } + pclose(p_file); + } + return RET_OK; +} + +int Cropper::GetOpMatchFiles() { + std::ifstream in_file(this->flags_->config_file_); + if (ValidFile(in_file, this->flags_->config_file_.c_str()) == RET_OK) { + MS_LOG(DEBUG) << this->flags_->config_file_.c_str(); + char buf[BUF_SIZE]; + while (!in_file.eof()) { + in_file.getline(buf, BUF_SIZE); + auto mapping = StringSplit(buf, DELIM_COMMA); + if (!mapping.empty()) { + String primitive = mapping[0]; + String type = mapping[1]; + String file = mapping[2]; + if (type == "kNumberTypeFloat32" || type == "kNumberTypeFloat16") { + for (auto op : this->fp32_operators_) { + if (schema::EnumNamePrimitiveType(op) == primitive) { + MS_LOG(DEBUG) << "kNumberTypeFloat32:" << mapping[2]; + this->archive_files_.insert(mapping[2]); + break; + } + } + } else if (type == "kNumberTypeInt8") { + for (auto op : this->int8_operators_) { + if (schema::EnumNamePrimitiveType(op) == primitive) { + MS_LOG(DEBUG) << "int8_operators_:" << mapping[2]; + this->archive_files_.insert(mapping[2]); + break; + } + } + } else if (type == "prototype") { + for (auto op : this->all_operators_) { + if (schema::EnumNamePrimitiveType(op) == primitive) { + MS_LOG(DEBUG) << "prototype:" << mapping[2]; + this->archive_files_.insert(mapping[2]); + break; + } + } + } else if (type == "common") { + MS_LOG(DEBUG) << "common:" << mapping[2]; + this->archive_files_.insert(mapping[2]); + } else { + MS_LOG(ERROR) << "invalid type symbol:" << type; + return RET_ERROR; + } + } + } + in_file.close(); + } else { + return RET_ERROR; + } + return RET_OK; +} +int Cropper::GetDiscardFileList() { + // discard_files_=all_files_-archive_files_ + for (const auto &archive : this->archive_files_) { + for (auto it = this->discard_files_.begin(); it != this->discard_files_.end();) { + if (*it == archive) { + it = this->discard_files_.erase(it); + } else { + it++; + } + } + } + return RET_OK; +} +int Cropper::CutPackage() { + String copy_bak_cmd = "cp " + this->flags_->package_file_ + " " + this->flags_->package_file_ + ".bak"; + String ar_cmd = "ar -d " + this->flags_->package_file_ + ".bak "; + for (const auto &file : this->discard_files_) { + ar_cmd.append(file).append(" "); + } + String copy_to_output_cmd = "cp " + this->flags_->package_file_ + ".bak " + this->flags_->output_file_ + " && rm " + + this->flags_->package_file_ + ".bak"; + int status; + status = system(copy_bak_cmd.c_str()); + if (status != 0) { + MS_LOG(ERROR) << copy_bak_cmd << " executor failed."; + return RET_ERROR; + } + status = system(ar_cmd.c_str()); + if (status != 0) { + MS_LOG(ERROR) << ar_cmd << " executor failed."; + return RET_ERROR; + } + status = system(copy_to_output_cmd.c_str()); + if (status != 0) { + MS_LOG(ERROR) << copy_to_output_cmd << " executor failed."; + return RET_ERROR; + } + return RET_OK; +} + +int RunCropper(int argc, const char **argv) { + CropperFlags flags; + int status; + status = flags.Init(argc, argv); + if (status == RET_SUCCESS_EXIT) { + return status; + } + if (status != RET_OK) { + MS_LOG(ERROR) << "Flags init Error : " << GetErrorInfo(status); + std::cerr << "Flags init Error : " << GetErrorInfo(status) << std::endl; + return status; + } + Cropper cropper(&flags); + + status = cropper.RunCropper(); + if (status == RET_OK) { + MS_LOG(INFO) << "CROPPER RESULT SUCCESS:" << status; + std::cout << "CROPPER RESULT SUCCESS:" << status << std::endl; + } else { + MS_LOG(ERROR) << "CROPPER RESULT FAILED:" << status << " " << GetErrorInfo(status); + std::cout << "CROPPER RESULT FAILED:" << status << " " << GetErrorInfo(status) << std::endl; + } + return status; +} +} // namespace cropper +} // namespace lite +} // namespace mindspore diff --git a/mindspore/lite/tools/lib_cropper/lib_cropper.h b/mindspore/lite/tools/lib_cropper/lib_cropper.h new file mode 100644 index 0000000000..d951910ade --- /dev/null +++ b/mindspore/lite/tools/lib_cropper/lib_cropper.h @@ -0,0 +1,68 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * 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. + */ + +#ifndef MINDSPORE_LITE_TOOLS_LIB_CROPPER_LIB_CROPPER_H_ +#define MINDSPORE_LITE_TOOLS_LIB_CROPPER_LIB_CROPPER_H_ + +#include +#include +#include +#include "include/model.h" +#include "tools/common/flag_parser.h" +#include "src/common/file_utils.h" +#include "src/common/utils.h" +#include "include/lite_session.h" +#include "tools/lib_cropper/cropper_flags.h" + +namespace mindspore::lite::cropper { + +class MS_API Cropper { + public: + explicit Cropper(CropperFlags *flags) : flags_(flags) {} + + ~Cropper() = default; + + int RunCropper(); + + int ReadPackage(); + + int GetModelFiles(); + + int GetModelOps(); + + int GetOpMatchFiles(); + + int GetDiscardFileList(); + + int CutPackage(); + + std::vector model_files_; + std::vector all_files_; + std::set archive_files_; + std::vector discard_files_; + + std::set all_operators_; + std::set int8_operators_; + std::set fp16_operators_; + std::set fp32_operators_; + + private: + CropperFlags *flags_; +}; + +int MS_API RunCropper(int argc, const char **argv); +} // namespace mindspore::lite::cropper +#endif // MINDSPORE_LITE_TOOLS_CROPPER_CROPPER_H_ diff --git a/mindspore/lite/tools/lib_cropper/main.cc b/mindspore/lite/tools/lib_cropper/main.cc new file mode 100644 index 0000000000..f0427c8a0d --- /dev/null +++ b/mindspore/lite/tools/lib_cropper/main.cc @@ -0,0 +1,23 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * 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. + */ + +#include "tools/lib_cropper/lib_cropper.h" +#include "include/version.h" + +int main(int argc, const char **argv) { + MS_LOG(INFO) << mindspore::lite::Version(); + return mindspore::lite::cropper::RunCropper(argc, argv); +}