From e02f1e07de559e3fcb3a6f081ce0a81c2f7cfde7 Mon Sep 17 00:00:00 2001 From: Megvii Engine Team Date: Thu, 28 Oct 2021 20:38:39 +0800 Subject: [PATCH] fix(ci): replace old lar with new lar GitOrigin-RevId: e4117ff53bb8d21af62e298a43a7ee3ad4f7e95b --- .../python/megengine/tools/load_network_and_run.py | 2 +- sdk/load-and-run/.gitignore | 4 - sdk/load-and-run/BUILD | 74 - sdk/load-and-run/CMakeLists.txt | 24 - sdk/load-and-run/Makefile | 29 - sdk/load-and-run/README.md | 144 -- sdk/load-and-run/main.cpp | 25 - sdk/load-and-run/src/json_loader.cpp | 299 ---- sdk/load-and-run/src/json_loader.h | 184 --- sdk/load-and-run/src/mgblar.cpp | 1639 -------------------- sdk/load-and-run/src/mgblar.h | 22 - sdk/load-and-run/src/npy.h | 627 -------- sdk/load-and-run/src/text_table.cpp | 108 -- sdk/load-and-run/src/text_table.h | 132 -- sdk/load-and-run/test/json_loader_test.cpp | 74 - 15 files changed, 1 insertion(+), 3386 deletions(-) delete mode 100644 sdk/load-and-run/.gitignore delete mode 100644 sdk/load-and-run/BUILD delete mode 100755 sdk/load-and-run/CMakeLists.txt delete mode 100644 sdk/load-and-run/Makefile delete mode 100644 sdk/load-and-run/README.md delete mode 100644 sdk/load-and-run/main.cpp delete mode 100644 sdk/load-and-run/src/json_loader.cpp delete mode 100644 sdk/load-and-run/src/json_loader.h delete mode 100644 sdk/load-and-run/src/mgblar.cpp delete mode 100644 sdk/load-and-run/src/mgblar.h delete mode 100644 sdk/load-and-run/src/npy.h delete mode 100644 sdk/load-and-run/src/text_table.cpp delete mode 100644 sdk/load-and-run/src/text_table.h delete mode 100644 sdk/load-and-run/test/json_loader_test.cpp diff --git a/imperative/python/megengine/tools/load_network_and_run.py b/imperative/python/megengine/tools/load_network_and_run.py index aebe1907..53629f2f 100755 --- a/imperative/python/megengine/tools/load_network_and_run.py +++ b/imperative/python/megengine/tools/load_network_and_run.py @@ -384,7 +384,7 @@ def main(): parser.add_argument( "--dump-cpp-model", help="write a C++ model that can be loaded by " - "megbrain/sdk/load-and-run; " + "megbrain/lite/load_and_run; " "this implies --embed-input", ) parser.add_argument( diff --git a/sdk/load-and-run/.gitignore b/sdk/load-and-run/.gitignore deleted file mode 100644 index 559c5734..00000000 --- a/sdk/load-and-run/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/load_and_run -/data -/*.gcda -/*.gcno diff --git a/sdk/load-and-run/BUILD b/sdk/load-and-run/BUILD deleted file mode 100644 index 29c79b22..00000000 --- a/sdk/load-and-run/BUILD +++ /dev/null @@ -1,74 +0,0 @@ -cc_library( - name = "mgblar", - copts = ["-std=c++14"], - srcs = [ - "src/mgblar.cpp", - "src/json_loader.cpp", - "src/text_table.cpp", - ], - hdrs = [ - "src/mgblar.h", - "src/json_loader.h", - "src/text_table.h", - "src/npy.h", - ], - features = if_opt([ - "no_exceptions", - "no_rtti", - ]), - includes = ["src"], - defines = ["MGB_ENABLE_FASTRUN=1"], - deps = ["//brain/megbrain:sdk-test"], -) - -cc_megvii_binary( - name = "load_and_run", - copts = ["-std=c++14"], - srcs = ["main.cpp"], - features = if_opt([ - "no_exceptions", - "no_rtti", - ]), - internal_deps = [":mgblar"], - visibility = ["//visibility:public"], -) - -cc_megvii_shared_object( - name = "load_and_run_shared", - copts = ["-std=c++14"], - srcs = ["main.cpp"], - features = if_opt([ - "no_exceptions", - "no_rtti", - ]), - internal_deps = [":mgblar"], - syms = ["main"], -) - -cc_megvii_binary( - name = "json_loader_test", - copts = ["-std=c++14"], - srcs = ["test/json_loader_test.cpp"], - internal_deps = [":mgblar"], -) - -cc_library( - name = "megbrain_ios_lar_lib", - srcs = [ - "src/mgblar.cpp", - ], - hdrs = [ - "src/mgblar.h", - ], - copts = ["-DMGB_NO_MAIN=1"], - features = if_opt([ - "no_exceptions", - "no_rtti", - ]), - deps = ["//brain/megbrain:sdk-test"], -) - -cc_megvii_static_library( - name = "megbrain_ios_lar", - deps = [":megbrain_ios_lar_lib"], -) diff --git a/sdk/load-and-run/CMakeLists.txt b/sdk/load-and-run/CMakeLists.txt deleted file mode 100755 index 5823ca52..00000000 --- a/sdk/load-and-run/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -include_directories(src) -file(GLOB_RECURSE SOURCES src/*.cpp main.cpp) - -add_executable(load_and_run ${SOURCES}) -target_link_libraries(load_and_run megbrain megdnn ${MGE_CUDA_LIBS}) - -# load_and_run_depends_shared always for CI check, please do not delete -if(BUILD_SHARED_LIBS) - add_executable(load_and_run_depends_shared ${SOURCES}) - target_link_libraries(load_and_run_depends_shared megengine) - if(WIN32 OR MSVC) - target_compile_definitions(load_and_run_depends_shared PRIVATE MGE_DLL_IMPORT_DATA) - endif() -endif() - -install(TARGETS load_and_run EXPORT ${MGE_EXPORT_TARGETS} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -if(BUILD_SHARED_LIBS) - install(TARGETS load_and_run_depends_shared EXPORT ${MGE_EXPORT_TARGETS} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -endif() - -if(MGE_WITH_TEST) - add_executable(json_loader_test test/json_loader_test.cpp src/json_loader.h src/json_loader.cpp) - target_link_libraries(json_loader_test megbrain megdnn ${MGE_CUDA_LIBS}) -endif() diff --git a/sdk/load-and-run/Makefile b/sdk/load-and-run/Makefile deleted file mode 100644 index 5c081d1f..00000000 --- a/sdk/load-and-run/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -include ../../Makefile - -MACHINE := $(shell $(MGB_CXX) -dumpmachine) - -ifneq (, $(findstring android, $(MACHINE))) - DEPS := $(MGB_LIB) ${MEGDNN_LIB} - CXXFLAGS := $(MGB_CXXFLAGS) -fuse-ld=gold -Isrc - LDFLAGS := -ldl -llog ${DEPS} -else - DEPS := $(MGB_LIB) ${MEGDNN_LIB} - CXXFLAGS := $(MGB_CXXFLAGS) -fuse-ld=gold -Isrc - LDFLAGS := -ldl ${DEPS} ${MGB_LDFLAGS} -endif - -TARGETS := load_and_run - -all: $(TARGETS) - -ifneq (,$(findstring gcov,$(MGB_LDFLAGS))) - LDFLAGS += --coverage -endif - -load_and_run: main.cpp src/* $(DEPS) - $(MGB_CXX) -o $@ main.cpp src/*.cpp $(CXXFLAGS) $(LDFLAGS) - -clean: - rm -f $(TARGETS) - -.PHONY: all clean diff --git a/sdk/load-and-run/README.md b/sdk/load-and-run/README.md deleted file mode 100644 index da4a75c0..00000000 --- a/sdk/load-and-run/README.md +++ /dev/null @@ -1,144 +0,0 @@ -# Load and Run - -Load a model and run, for testing/debugging/profiling. - -## Build - - - -### Build with cmake - -Build MegEngine from source following [README.md](../../README.md). It will also produce the executable, `load_and_run`, which loads a model and runs the test cases attached to the model. - - - - -## Dump Model with Test Cases Using [dump_with_testcase_mge.py](dump_with_testcase_mge.py) - -### Step 1 - -Dump the model by calling the python API `megengine.jit.trace.dump()`. - -### Step 2 - -Append the test cases to the dumped model using [dump_with_testcase_mge.py](dump_with_testcase_mge.py). - -The basic usage of [dump_with_testcase_mge.py](dump_with_testcase_mge.py) is - -``` -python3 dump_with_testcase_mge.py model -d input_description -o model_with_testcases - -``` - -where `model` is the file dumped at step 1, `input_description` describes the input data of the test cases, and `model_with_testcases` is the saved model with test cases. - -`input_description` can be provided in the following ways: - -1. In the format `var0:file0;var1:file1...` meaning that `var0` should use - image file `file0`, `var1` should use image `file1` and so on. If there - is only one input var, the var name can be omitted. This can be combined - with `--resize-input` option. -2. In the format `var0:#rand(min, max, shape...);var1:#rand(min, max)...` - meaning to fill the corresponding input vars with uniform random numbers - in the range `[min, max)`, optionally overriding its shape. - -For more usages, run - -``` -python3 dump_with_testcase_mge.py --help -``` - -### Example - -1. Obtain the model file by running [xornet.py](../xor-deploy/xornet.py). - -2. Dump the file with test cases attached to the model. - - ``` - python3 dump_with_testcase_mge.py xornet_deploy.mge -o xornet.mge -d "#rand(0.1, 0.8, 4, 2)" - ``` - -3. Verify the correctness by running `load_and_run` at the target platform. - - ``` - load_and_run xornet.mge - ``` - -## `load_and_run --input` the dumped mge file - -You can also use `--input` to set mge file's input, this argument support these 4 formats: - -1. PPM/PGM image file. - - PPM/PGM is supported by OpenCV and simple to parse, you can easily use `cv::imwrite` to generate one. - - ``` - load_and_run model.mge --input "data:image.ppm" - ``` - - `data` is blob name and `image.ppm` is file path, we use `:` to seperate key and value. Please note that `"` is necessary in terminal. - -2. npy file. - - npy is `Numpy` file format, here is a Python example - - ``` - import numpy as np - import cv2 - mat = cv2.imread('file.jpg') - np.save('image.npy', mat) - arr = np.array([[[1.1, 1.2],[100, 200.0]]], dtype=np.float32) - np.save('bbox.npy', arr) - ``` - - then `load_and_run` the model - - ``` - load_and_run model.mge --input data:image.npy;bbox.npy - ``` - -3. json format. - - For json format, you have to identify data type and blob shape. Here is a Python example - - ``` - import numpy as np - import json - import cv2 - bbox = np.array([[[1.1, 1.2],[100, 200.0]]], dtype=np.float32) - obj = dict() - obj['shape'] = bbox.shape - obj['raw'] = bbox.flatten().tolist() - obj['type'] = str(bbox.dtype) - json_object = dict() - json_object['bbox'] = obj - json_str = json.dumps(json_object) - with open('bbox.json', 'w') as f: - f.write(json_str) - f.flush() - f.close() - ``` - - The json loader in `load_and_run` is not fully implement [RFC7159](https://tools.ietf.org/html/rfc7159), it does not support `boolean` and `utf` string format which is useless during inference. - - Now let's `load-and-run` the model with json file - - ``` - load_and_run model.mge --input data:image.npy:bbox:bbox.json - ``` - - Mutiple key-value pair could be seperated with `;`. - -4. plain string format. - - Also, you can give the value directly - - ``` - load_and_run model.mge --input data:image.ppm --input "bbox:[0,0],[200.0,200.0]" --input "batchid:0" - ``` - - 1. `bbox` shape is `[1,2,2]` for `[0,0],[200.0,200.0]`. In order to facilitate user experience, the string parser would add an extra axis for input, thus `bbox:0` is correspond to `[1]` and `bbox:[0]` means that the shape is `[1,1]` - - 2. Since we can only identify `int32` and `float32` from this format, don't forget `.` for float number. diff --git a/sdk/load-and-run/main.cpp b/sdk/load-and-run/main.cpp deleted file mode 100644 index b2d643f4..00000000 --- a/sdk/load-and-run/main.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/** - * \file sdk/load-and-run/main.cpp - * MegEngine is Licensed under the Apache License, Version 2.0 (the "License") - * - * Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - */ - -#include "mgblar.h" -#include "megbrain/common.h" - -int main(int argc, char **argv) { - MGB_TRY { - return mgb_load_and_run_main(argc, argv); - } MGB_CATCH (std::exception &exc, { - fprintf(stderr, "caught exception: %s\n", exc.what()); - return -2; - }) -} - -// vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}} - diff --git a/sdk/load-and-run/src/json_loader.cpp b/sdk/load-and-run/src/json_loader.cpp deleted file mode 100644 index 13b85dd0..00000000 --- a/sdk/load-and-run/src/json_loader.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/** - * \file sdk/load-and-run/src/json_loader.cpp - * MegEngine is Licensed under the Apache License, Version 2.0 (the "License") - * - * Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - */ - -#include "json_loader.h" - -using namespace mgb; - -template -T* JsonLoader::Value::safe_cast() { - T* ptr = (T*)(this); - if (nullptr == ptr) { - fprintf(stderr, "cast ptr is null\n"); - } - return ptr; -} - -std::unique_ptr& JsonLoader::Value::operator[]( - const std::string& key) { - mgb_assert(Type::OBJECT == m_type); - auto t = safe_cast(); - return t->m_obj.at(key); -} - -std::unique_ptr& JsonLoader::Value::operator[]( - const size_t index) { - mgb_assert(Type::ARRAY == m_type); - auto t = safe_cast(); - return t->m_obj[index]; -} - -std::map>& -JsonLoader::Value::objects() { - mgb_assert(Type::OBJECT == m_type); - auto t = safe_cast(); - return t->m_obj; -} - -size_t JsonLoader::Value::len() { - if (Type::ARRAY == m_type) { - auto t = safe_cast(); - return t->m_obj.size(); - } else if (Type::OBJECT == m_type) { - auto t = safe_cast(); - return t->m_obj.size(); - } - return 0; -} - -megdnn::SmallVector>& -JsonLoader::Value::array() { - mgb_assert(Type::ARRAY == m_type); - auto t = safe_cast(); - return t->m_obj; -} - -double JsonLoader::Value::number() { - mgb_assert(Type::NUMBER == m_type); - auto t = safe_cast(); - return t->value(); -} - -std::string JsonLoader::Value::str() { - if (Type::STRING == m_type) { - auto t = safe_cast(); - return t->value(); - } - return std::string(); -} - -void JsonLoader::expect(char c) { - mgb_assert(c == (*m_buf)); - m_buf++; -} - -void JsonLoader::skip_whitespace() { - const char* p = m_buf; - while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') { - ++p; - } - m_buf = p; -} - -std::unique_ptr JsonLoader::parse_object() { - expect('{'); - skip_whitespace(); - - std::unique_ptr ret; - JsonLoader::ObjectValue* pObject = new JsonLoader::ObjectValue(); - - if ('}' == *m_buf) { - m_buf = m_buf + 1; - ret.reset((JsonLoader::Value*)(pObject)); - return ret; - } - - while (true) { - std::unique_ptr key = parse_string(); - if (m_state != State::OK) { - return ret; - } - - skip_whitespace(); - if (':' != (*m_buf)) { - m_state = State::MISS_COLON; - return ret; - } - m_buf++; - skip_whitespace(); - - std::unique_ptr pVal = parse_value(); - if (m_state != State::OK) { - return ret; - } - - if (pObject->m_obj.find(pVal->str()) != pObject->m_obj.end()) { - m_state = State::KEY_NOT_UNIQUE; - return ret; - } - - pObject->m_obj.insert(std::make_pair(key->str(), std::move(pVal))); - - skip_whitespace(); - if (',' == (*m_buf)) { - m_buf++; - skip_whitespace(); - } else if ('}' == (*m_buf)) { - m_buf++; - break; - } else { - m_state = State::MISS_BRACE; - break; - } - } - - ret.reset((JsonLoader::Value*)(pObject)); - return ret; -} - -std::unique_ptr JsonLoader::parse_array() { - expect('['); - skip_whitespace(); - - std::unique_ptr ret; - JsonLoader::ArrayValue* pArray = new JsonLoader::ArrayValue(); - - if (']' == *m_buf) { - m_buf = m_buf + 1; - - ret.reset((JsonLoader::Value*)(pArray)); - return ret; - } - - while (true) { - std::unique_ptr pVal = parse_value(); - if (m_state != State::OK) { - mgb_assert(0, "parse value failed during pase array"); - return ret; - } - - pArray->m_obj.emplace_back(pVal.get()); - pVal.release(); - - skip_whitespace(); - if (',' == *m_buf) { - m_buf++; - skip_whitespace(); - } else if (']' == *m_buf) { - m_buf++; - break; - } else { - m_state = State::BAD_ARRAY; - return ret; - } - } - - ret.reset((JsonLoader::Value*)(pArray)); - return ret; -} - -std::unique_ptr JsonLoader::parse_string() { - expect('\"'); - - std::unique_ptr ret; - JsonLoader::StringValue* pStr = new JsonLoader::StringValue(); - - const char* p = m_buf; - while (true) { - if (*p == '\"') { - p++; - break; - } else { - pStr->m_value += (*p); - p++; - } - } - m_buf = p; - ret.reset((JsonLoader::Value*)(pStr)); - return ret; -} - -std::unique_ptr JsonLoader::parse_number() { - const char* p = m_buf; - - auto loop_digit = [this](const char*& p) { - if (not std::isdigit(*p)) { - m_state = State::BAD_DIGIT; - return; - } - while (std::isdigit(*p)) { - p++; - } - return; - }; - - if (*p == '-') - p++; - if (*p == '0') - p++; - else { - loop_digit(std::ref(p)); - } - if (*p == '.') { - p++; - loop_digit(std::ref(p)); - } - - if (*p == 'e' || *p == 'E') { - p++; - if (*p == '+' || *p == '-') - p++; - loop_digit(std::ref(p)); - } - JsonLoader::NumberValue* pNum = new JsonLoader::NumberValue(); - pNum->m_value = strtod(m_buf, nullptr); - - m_buf = p; - - std::unique_ptr ret; - ret.reset((JsonLoader::Value*)(pNum)); - return ret; -} - -std::unique_ptr JsonLoader::parse_value() { - switch (*m_buf) { - case '[': - return parse_array(); - case '{': - return parse_object(); - case '\"': - return parse_string(); - case '\0': - m_state = State::BAD_TYPE; - break; - default: - return parse_number(); - } - return nullptr; -} - -std::unique_ptr JsonLoader::load(const char* content, - const size_t size) { - m_buf = content; - skip_whitespace(); - std::unique_ptr value = parse_value(); - skip_whitespace(); - - if (m_state != State::OK) { - return nullptr; - } - mgb_assert(size == static_cast(m_buf - content)); - - return value; -} - -std::unique_ptr JsonLoader::load(const char* path) { - std::unique_ptr fin( - std::fopen(path, "rb"), [](std::FILE* fp) { std::fclose(fp); }); - - mgb_assert(fin.get(), "failed to open %s: %s", path, strerror(errno)); - std::fseek(fin.get(), 0, SEEK_END); - const size_t size = ftell(fin.get()); - std::fseek(fin.get(), 0, SEEK_SET); - - std::unique_ptr buf(static_cast(malloc(size))); - - auto nr = std::fread(buf.get(), 1, size, fin.get()); - mgb_assert(nr == size); - - return load(buf.get(), size); -} diff --git a/sdk/load-and-run/src/json_loader.h b/sdk/load-and-run/src/json_loader.h deleted file mode 100644 index 6e65a782..00000000 --- a/sdk/load-and-run/src/json_loader.h +++ /dev/null @@ -1,184 +0,0 @@ -/** - * \file sdk/load-and-run/src/json_loader.h - * MegEngine is Licensed under the Apache License, Version 2.0 (the "License") - * - * Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include "megbrain/common.h" -#include "megdnn/thin/small_vector.h" - -namespace mgb { - -class JsonLoader { -public: - class Value { - protected: - enum struct Type : uint8_t { UNKNOWN, NUMBER, STRING, OBJECT, ARRAY }; - Type m_type; - - public: - template - T* safe_cast(); - - Value() { m_type = Type::UNKNOWN; } - - Value(Type type) : m_type(type) {} - - virtual ~Value() {} - - bool is_array() { return Type::ARRAY == m_type; } - - bool is_object() { return Type::OBJECT == m_type; } - - bool is_number() { return Type::NUMBER == m_type; } - - bool is_str() { return Type::STRING == m_type; } - - std::unique_ptr& operator[](const std::string& key); - - std::unique_ptr& operator[](const size_t index); - - std::map>& objects(); - - size_t len(); - - megdnn::SmallVector>& array(); - - double number(); - - std::string str(); - }; - - void expect(char c); - - void skip_whitespace(); - - std::unique_ptr parse_object(); - - std::unique_ptr parse_array(); - - std::unique_ptr parse_string(); - - std::unique_ptr parse_number(); - - std::unique_ptr parse_value(); - - enum struct State : uint8_t { - OK = 0, - BAD_TYPE, - BAD_DIGIT, - BAD_ARRAY, - MISS_COLON, - MISS_BRACE, - KEY_NOT_UNIQUE - }; - - JsonLoader() { m_state = State::OK; } - - std::unique_ptr load(const char* content, const size_t size); - - std::unique_ptr load(const char* path); - - class NumberValue final : public Value { - friend std::unique_ptr JsonLoader::parse_number(); - double m_value; - - public: - NumberValue() : Value(Type::NUMBER) {} - - double value() { return m_value; } - }; - - class StringValue final : public Value { - std::string m_value; - - public: - StringValue() : Value(Type::STRING) {} - - std::string value() { return m_value; } - - friend std::unique_ptr JsonLoader::parse_string(); - }; - - class ArrayValue final : public Value { - megdnn::SmallVector> m_obj; - - public: - ArrayValue() : Value(Type::ARRAY) {} - - ArrayValue(ArrayValue& arr) : Value(arr) { - m_obj.clear(); - for (auto& item : arr.m_obj) { - m_obj.emplace_back(item.get()); - item.release(); - } - } - - ArrayValue(ArrayValue&& arr) : Value(arr) { - m_obj.clear(); - for (auto& item : arr.m_obj) { - m_obj.emplace_back(item.get()); - item.release(); - } - } - - friend std::unique_ptr JsonLoader::parse_array(); - friend std::unique_ptr& JsonLoader::Value:: - operator[](const size_t index); - friend megdnn::SmallVector>& - JsonLoader::Value::array(); - friend size_t JsonLoader::Value::len(); - }; - - class ObjectValue final : public Value { - std::map> m_obj; - - public: - ObjectValue() : Value(Type::OBJECT) {} - - ObjectValue(ObjectValue& arr) : Value(arr) { - m_obj.clear(); - for (auto itra = arr.m_obj.begin(); itra != arr.m_obj.end(); - ++itra) { - m_obj.emplace( - std::make_pair(itra->first, std::move(itra->second))); - } - } - - ObjectValue(ObjectValue&& arr) : Value(arr) { - m_obj.clear(); - for (auto itra = arr.m_obj.begin(); itra != arr.m_obj.end(); - ++itra) { - m_obj.emplace( - std::make_pair(itra->first, std::move(itra->second))); - } - } - - friend std::unique_ptr JsonLoader::parse_object(); - friend std::unique_ptr& JsonLoader::Value:: - operator[](const std::string&); - friend std::map>& - JsonLoader::Value::objects(); - friend size_t JsonLoader::Value::len(); - }; - -private: - const char* m_buf; - State m_state; -}; - -} // namespace mgb diff --git a/sdk/load-and-run/src/mgblar.cpp b/sdk/load-and-run/src/mgblar.cpp deleted file mode 100644 index da41f919..00000000 --- a/sdk/load-and-run/src/mgblar.cpp +++ /dev/null @@ -1,1639 +0,0 @@ -/** - * \file sdk/load-and-run/src/mgblar.cpp - * MegEngine is Licensed under the Apache License, Version 2.0 (the "License") - * - * Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - */ - -#include "./mgblar.h" -#include "./json_loader.h" -#include "./npy.h" -#include "./text_table.h" - -#include "megbrain/comp_node_env.h" -#include "megbrain/gopt/inference.h" -#include "megbrain/graph/extern_copr_api.h" -#include "megbrain/opr/dnn/convolution.h" -#include "megbrain/opr/io.h" -#include "megbrain/opr/search_policy/algo_chooser_helper.h" -#include "megbrain/opr/utility.h" -#include "megbrain/plugin/cpu_dispatch_checker.h" -#include "megbrain/plugin/num_range_checker.h" -#include "megbrain/plugin/opr_io_dump.h" -#include "megbrain/plugin/profiler.h" -#include "megbrain/plugin/var_value_checker.h" -#include "megbrain/serialization/extern_c_opr.h" -#include "megbrain/serialization/serializer.h" -#include "megbrain/utils/debug.h" -#include "megbrain/utils/infile_persistent_cache.h" - -#include "megbrain/system.h" -#include "megbrain/version.h" -#include "megdnn/version.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_WIN32) -#include -#define F_OK 0 -#define access(a, b) _access(a, b) -#elif __linux__ || __unix__ || __APPLE__ -#include -#include -#endif - -#if MGB_ENABLE_TENSOR_RT -#include "megbrain/tensorrt/tensorrt_engine_cache.h" -#endif - -using namespace mgb; - -namespace { - -const char* OPTIONS_DESC = -R"__usage__( - --cpu|--cpu-default -)__usage__" -R"__usage__( - Require to compute on CPU or OpenCL. By default CUDA is used if available, - and CPU is used if CUDA is not available. Use --cpu-default to compute on - CPU and dispatch all tasks in the caller thread. - --multithread|--multithread-default - Use --multithread to compute on CPU with multi threads. - Use --multithread-default to compute on CPU with multi threads and - the caller thread is main thread of the multi thread pool, follow by - thread number - --multi-thread-core-ids - The multi thread affinity core set, separated with ',', the number of digital - will be the thread number. for example:--multi-thread-core-ids "0,1,2,3", the - number thread if 4,the main thread binding the last core '3', - for best performance, the main thread should binding to the fast core. - --profile|--profile-host - Write profiling result to given file. The output file is in JSON format and - can be processed by scripts in MegHair/utils/debug. - Note: - For some backends (like opencl), special options need to be enabled for - profiling device time, which may cause additional overhead and make it - hard to profile host time. Use --profile-host to focus on host time - profiling. - --input [ filepath | string] - Set up inputs for megbrain model. for example: --data image.ppm --data - param.json --data bbox:bbox.npy@batchid:b.npy --data rect:[0,0,227,227]; - batchid:0,1,2,3. --io-dump or --bin-io-dump - should be enabled at the same time. - --model-info - Format and display model input/output tensor info. - --io-dump | --bin-io-dump - Dump input/output values of all internal variables to output file or - directory, in text or binary format. The binary file can be parsed by - `megbrain.plugin.load_tensor_binary`. - --io-dump-stdout | --io-dump-stderr - Dump input/output values of all internal variables to stdout or stderr in text format - --bin-out-dump - Dump output tensor values in binary format to given directory. - --iter - Number of iterations to run for each testcase. - --warmup-iter - Number of warm-up iterations, which are not included in the time statistics. - --range - Enable tensor value range check. Exception would be raised if the absolute - value of any element of any variable does not fit in given range. This can - be used to debug NaN values. - --check-dispatch - Enable CPU dispatch checker, which prints a warning message if on operator - does not the dispatch function. This is used to find potential bugs in - MegDNN. - --check-var-value - Enable VarValueChecker plugin. Refer to its doc for more details. - --no-sanity-check - Disable var sanity check on the first run. Var sanity check is enabled on - the first-time execution by default, and can be used to find some potential - memory access errors in the operator implementation. - --disable-mem-opt - Disable memory optimizations. This is used to check whether memory - optimization is the cause for unexpected behavior. - --fake-first - Enable fake exec for the first run. In fake exec mode, some initialization - job would be done, but no actual computing is performed. This can be used in - an SDK right after loading the model to reduce execution latency in the real - fist-time computing. It requires input shapes to be correctly setup. - --const-shape - Set `GraphLoadConfig::const_var_shape` to true before loading the graph. - This can be used to reduce memory usage since some static inference data - structures can be omitted. - --share-param-mem - Share the memory used by model params with model storage. This can be used - to reduce memory usage when computing on CPU. - --record-comp-seq | --record-comp-seq2 - Record the computing sequence, in level 1 or 2. It reduces overhead of API - calls of some asynchronous computing devices, especially for OpenCL. In - level 2 the computing graph can be destructed to reduce memory usage. Read - the doc of `ComputingGraph::Options::comp_node_seq_record_level` for more - details. -)__usage__" -#ifndef __IN_TEE_ENV__ -#if MGB_ENABLE_JSON -R"__usage__( - --get-static-mem-info - Record the static graph's static memory info. -)__usage__" -#endif -#endif -#if MGB_ENABLE_FASTRUN -R"__usage__( - --full-run - Enable full-run mode. Operators with multiple algorithms would be profiled - on the real device with actual input shapes, all algorithms will be profiled - include naive algorithms. - See `mgb::gopt::enable_opr_algo_profiling_inplace` for more details. - --fast-run - Enable fast-run mode. Operators with multiple algorithms would be profiled - on the real device with actual input shapes, this mode will only profile the - well optimized algorithms to get the profile result fast. - See `mgb::gopt::enable_opr_algo_profiling_inplace` for more details. -)__usage__" -#endif -R"__usage__( - --fast-run-algo-policy - It will read the cache file before profile, and save new fastrun in cache file. - --fast-run-shared-batch-size - Set the batch size used during fastrun, Note that it may not be the same as the actual running batch size - --binary-equal-between-batch - Each batch of output is promised binary equal if each batch of input is binary equal. - Note that if this option is turned on, `--reproducible` will also be turned on. - --reproducible - Enable choose algo which is reproducible. It mainly used for cudnn algos. - See https://docs.nvidia.com/deeplearning/sdk/cudnn-developer-guide/index.html#reproducibility - for more details. - --wait-gdb - Print PID and wait for a line from stdin before starting execution. Useful - for waiting for gdb attach. - --c-opr-lib - Load external operator library. It must implement MGB_C_OPR_INIT_FUNC_STR as the - entry point. - --c-opr-lib-with-param - Run c opr lib with param, use to benchmark speed and check result, need c opr loader implemente - `copr_param_device_ptr_malloc, copr_param_device_ptr_free and copr_param_device_ptr_h2d symbols`. - --thread - Number of threads to run concurrently. All threads perform the same work of - loading and executing models. This is used for test thread safety, not for - speed up on multiple cores. - --disable-assert-throw - Do not throw exception in case AssertEqual fails. Note that the exit code - would also be zero if this option is enabled. This should only be used for - debug. - --copy-to-host - Whether copy output from device to host. - This is used for checking the performance in real scenarios including output copy. - --workspace-limit - set workspace_limit for execution strategy for oprs with multiple algorithms. - The default is SIZE_MAX(bytes). - --verbose - Increase verbosity for megbrain log. -)__usage__" -#if MGB_ENABLE_TENSOR_RT -R"__usage__( - --tensorrt - Execute supported operators with TensorRT. Can only be used on Nvidia GPUs, - i.e. comp node is xpu or gpu. - --tensorrt-cache - Set the TensorRT engine cache path for serialized prebuilt ICudaEngine -)__usage__" -#endif -R"__usage__( - --enable-jit - Execute supported operators with JIT(now only support NVRTC). Can only be used on Nvidia GPUs. -)__usage__" -R"__usage__( - --enable-chwn4 - Execute operators with kernels implemented in MegDNN with CHWN4 tensor format. Can only be used - on Nvidia GPUs, whose compute capability is above 6.1. -)__usage__" -R"__usage__( - --enable-nchw44 - Execute operators with kernels implemented in MegDNN with NCHW44 tensor format. This can only - be used on arm of armv7 and arm64, support data tyep of float32, qint8 and int8x8x16. -)__usage__" -R"__usage__( - --enable-nchw88 - Execute operators with kernels implemented in MegDNN with NCHW88 tensor format. This can only - be used on x86 with data type float. -)__usage__" -R"__usage__( - --enable-nchw44-dot - Execute operators with kernels implemented in MegDNN with NCHW44-DOT tensor format. This Can - only be used on arm32 and arm64 with dot-product supported, and only support qint8 model -)__usage__" -R"__usage__( - --weight-preprocess - Execute operators with weight preprocess, which can optimize the operator execution time with - algo of winograd, im2col ,etc., but it may consume more memory. -)__usage__" -R"__usage__( - --enable-fuse-preprocess - Fusion astype\pad_channel\dimshuffle and etc opr from h2d op -)__usage__" -R"__usage__( - --enable-nchw64 - Execute operators with kernels implemented in MegDNN with NCHW64 tensor format. Can only be used - on Nvidia GPUs, which natively support fast int4 tensorcore inference. -)__usage__" -R"__usage__( - --layout-transform [cuda|x86|arm|opencl|unspec] - Enable global layout transform optimization for computing graph. User should specify the device target for the optimization, and a series of passes will be applied on the computing graph. The passes will benchmark the elapsed time of operators on different tensor layouts, and select fastest implementation for the operators. The optimization process will take some time. The default target is unspec, which all the available for operators will be profiled. So the optimize time will be longer. - --layout-transform-dump - The computing graph after global layout transform will be dumped to the given file path. - --layout-transform-verify - After applying the layout transform optimization, the results of the computing graph before and after layout transform passes will be compared to verify the correctness of the passes. -)__usage__" -R"__usage__( -)__usage__" -; - - - -struct DataParser { - struct Brace { - std::weak_ptr parent; - std::vector> chidren; - }; - - void feed(const std::string& path) { - std::string blob_name = "data", blob_string = path; - size_t sep = path.find(":"); - if (sep != std::string::npos) { - blob_name = path.substr(0, sep); - blob_string = path.substr(sep + 1); - } - - auto endWith = [blob_string](std::string suffix) -> bool { - return blob_string.rfind(suffix) == - (blob_string.length() - suffix.length()); - }; - - if (endWith(".ppm") || endWith(".pgm")) { - parse_image(blob_name, blob_string); - } else if (endWith(".json")) { - parse_json(blob_string); - } else if (endWith(".npy")) { - parse_npy(blob_name, blob_string); - } else { - parse_string(blob_name, blob_string); - } - } - - std::map inputs; - -private: - void parse_json(const std::string& path) { - JsonLoader json; - std::shared_ptr root = json.load(path.c_str()); - - mgb_assert(root != nullptr, "parse json %s fail", path.c_str()); - - // parse json to data map - const std::string SHAPE = "shape", TYPE = "type", RAW = "raw"; - for (auto& item : root->objects()) { - auto&& value = *item.second; - auto&& shape = value[SHAPE]; - mgb_assert(shape->is_array()); - - auto&& type = value[TYPE]; - mgb_assert(type->is_str()); - - auto&& raw = value[RAW]; - mgb_assert(raw->is_array()); - - megdnn::SmallVector data_shape; - for (auto&& shape_ptr : shape->array()) { - data_shape.append( - {static_cast(std::round(shape_ptr->number()))}); - } - - // get type - const std::map type_map = { - {"float32", dtype::Float32()}, {"float", dtype::Float32()}, - {"int32", dtype::Int32()}, {"int", dtype::Int32()}, - {"int8", dtype::Int8()}, {"uint8", dtype::Uint8()}}; - - const std::string& type_str = type->str(); - mgb_assert(type_map.find(type_str) != type_map.end(), - "unknown json data type for --data"); - - DType datatype = type_map.at(type_str); - HostTensorND hv; - hv.comp_node(mgb::CompNode::default_cpu(), true) - .dtype(datatype) - .resize(data_shape); - dt_byte* raw_ptr = hv.raw_ptr(); - size_t elem_size = datatype.size(); - - // get raw - const size_t array_size = raw->len(); - for (size_t idx = 0; idx < array_size; ++idx) { - double tmp = (*raw)[idx]->number(); - - switch (datatype.enumv()) { - case megdnn::DTypeEnum::Int32: { - int32_t ival = std::round(tmp); - memcpy(raw_ptr + idx * elem_size, &ival, elem_size); - } break; - case megdnn::DTypeEnum::Uint8: - case megdnn::DTypeEnum::Int8: { - int8_t cval = std::round(tmp); - memcpy(raw_ptr + idx, &cval, sizeof(int8_t)); - } break; - case megdnn::DTypeEnum::Float32: { - float fval = tmp; - memcpy(raw_ptr + idx * elem_size, &fval, elem_size); - } break; - default: - break; - } - } - - inputs.insert(std::make_pair(item.first, std::move(hv))); - } - } - - void parse_image(const std::string& name, const std::string& path) { - // load ppm/pgm - std::ifstream fin; - fin.open(path, std::ifstream::binary | std::ifstream::in); - mgb_assert(fin.is_open(), "open file %s failed for --input", - path.c_str()); - - size_t w = 0, h = 0, channel = 0; - char buf[128] = {0}; - - fin.getline(buf, 128); - if ('5' == buf[1]) { - channel = 1; - } else if ('6' == buf[1]) { - channel = 3; - } else { - mgb_assert(0, "not a formal ppm/pgm"); - } - - while (fin.getline(buf, 128)) { - // skip OCV comment, check - // https://github.com/opencv/opencv/pull/17006 - if (buf[0] == '#') { - continue; - } - break; - } - std::stringstream ss; - ss << std::string(buf); - ss >> w; - ss >> h; - - mgb_assert(w > 0 and h > 0); - - HostTensorND hv; - hv.comp_node(mgb::CompNode::default_cpu(), true) - .dtype(dtype::Uint8()) - .resize({1, h, w, channel}); - - fin.read((char*)(hv.raw_ptr()), hv.layout().total_nr_elems()); - fin.close(); - inputs.insert(std::make_pair(name, std::move(hv))); - } - - void parse_npy(const std::string& name, const std::string& path) { - std::string type_str; - std::vector stl_shape; - std::vector raw; - npy::LoadArrayFromNumpy(path, type_str, stl_shape, raw); - - megdnn::SmallVector shape; - for (auto val : stl_shape) { - shape.append({static_cast(val)}); - } - - const std::map type_map = { - {"f4", dtype::Float32()}, - {"i4", dtype::Int32()}, - {"u2", dtype::Uint16()}, - {"i2", dtype::Int16()}, - {"i1", dtype::Int8()}, - {"u1", dtype::Uint8()}, - }; - - megdnn::DType hv_type; - for (auto& item : type_map) { - if (type_str.find(item.first) != std::string::npos) { - hv_type = item.second; - break; - } - } - - HostTensorND hv; - hv.comp_node(mgb::CompNode::default_cpu(), true) - .dtype(hv_type) - .resize(shape); - dt_byte* raw_ptr = hv.raw_ptr(); - memcpy(raw_ptr, raw.data(), raw.size()); - - inputs.insert(std::make_pair(name, std::move(hv))); - } - - void parse_string(const std::string name, const std::string& str) { - // data type - megdnn::DType data_type = dtype::Int32(); - if (str.find(".") != std::string::npos or - str.find(".") != std::string::npos) { - data_type = dtype::Float32(); - } - // shape - size_t number_cnt = 0; - - std::shared_ptr brace_root = std::make_shared(); - std::shared_ptr cur = brace_root; - for (size_t i = 0; i < str.size(); ++i) { - char c = str[i]; - if (c == '[') { - std::shared_ptr child = std::make_shared(); - child->parent = cur; - cur->chidren.emplace_back(child); - cur = child; - } else if (c == ']') { - cur = cur->parent.lock(); - } else if (c == ',') { - number_cnt++; - } - continue; - } - ++number_cnt; - - mgb_assert(cur == brace_root, "braces not closed for --input"); - megdnn::SmallVector shape; - cur = brace_root; - while (not cur->chidren.empty()) { - shape.append({cur->chidren.size()}); - number_cnt /= cur->chidren.size(); - cur = cur->chidren[0]; - } - mgb_assert(number_cnt > 0); - shape.append({number_cnt}); - - // data - std::string json_arr; - for (size_t i = 0; i < str.size(); ++i) { - char c = str[i]; - if (c != '[' and c != ']') { - json_arr += c; - } - } - json_arr = "[" + json_arr + "]"; - - // reuse json parser to resolve raw data - JsonLoader json; - std::shared_ptr json_root = - json.load(json_arr.data(), json_arr.size()); - mgb_assert(json_root != nullptr, "parse json fail in parse_string"); - - HostTensorND hv; - hv.comp_node(mgb::CompNode::default_cpu(), true) - .dtype(data_type) - .resize(shape); - dt_byte* raw_ptr = hv.raw_ptr(); - - const size_t array_len = json_root->len(); - const size_t elem_size = data_type.size(); - for (size_t idx = 0; idx < array_len; ++idx) { - double tmp = json_root->array()[idx]->number(); - switch (data_type.enumv()) { - case megdnn::DTypeEnum::Int32: { - int32_t ival = std::round(tmp); - memcpy(raw_ptr + idx * elem_size, &ival, elem_size); - } break; - case megdnn::DTypeEnum::Float32: { - float fval = tmp; - memcpy(raw_ptr + idx * elem_size, &fval, elem_size); - } break; - default: - break; - } - } - inputs.insert(std::make_pair(name, std::move(hv))); - }; -}; - -struct Args { - int args_parse_ret = 0; - - std::string model_path; - struct COprArgs { - //! for run c opr - bool is_run_c_opr = false; - bool is_run_c_opr_with_param = false; - typedef void (*COPR_PARAM_DEVICE_PTR_MEM_T)(ExternCOprParam* param); - typedef void (*COPR_PARAM_DEVICE_PTR_H2D_T)( - ExternCOprParam* param, void* host_ptr, - size_t extern_device_tensor_id); - COPR_PARAM_DEVICE_PTR_MEM_T copr_param_device_ptr_malloc = nullptr; - COPR_PARAM_DEVICE_PTR_MEM_T copr_param_device_ptr_free = nullptr; - COPR_PARAM_DEVICE_PTR_H2D_T copr_param_device_ptr_h2d = nullptr; - }; - - COprArgs c_opr_args; - - bool display_model_info = false; - bool disable_assert_throw = false; - bool share_param_mem = false; -#if MGB_ENABLE_FASTRUN - bool use_full_run = false; - bool use_fast_run = false; -#endif - bool reproducible = false; - std::string fast_run_cache_path; -#ifndef __IN_TEE_ENV__ -#if MGB_ENABLE_JSON - std::string static_mem_log_dir_path; -#endif -#endif - bool copy_to_host = false; - int nr_run = 10; - int nr_warmup = 1; - int nr_thread = 1; - int multithread_number = 1; - size_t workspace_limit = SIZE_MAX; - std::vector data_files; - serialization::GraphLoader::LoadResult load_ret; -#if MGB_ENABLE_JSON - std::unique_ptr profiler; -#endif - std::string profiler_output; - std::string bin_out_dump; - - std::unique_ptr iodump; - std::unique_ptr num_range_checker; - std::unique_ptr cpu_dispatch_checker; - std::unique_ptr var_value_checker; - serialization::GraphLoader::LoadConfig load_config; - thin_function affinity_cb; - - bool layout_transform = false; - gopt::GraphTuningOptions::Target layout_transform_target = - gopt::GraphTuningOptions::Target::UNSPEC; - std::string layout_transform_dump_path; - - static Args from_argv(int argc, char **argv); -}; - -uint32_t read_nr_test(serialization::InputFile &fin) { - char magic[8]; - fin.read(magic, sizeof(magic)); - if (strncmp(magic, "mgbtest0", 8)) { - fin.rewind(); - return 0; - } - uint32_t ret; - fin.read(&ret, sizeof(ret)); - return ret; -} - -size_t get_file_size(FILE *fptr) { - fseek(fptr, 0, SEEK_END); - size_t size = ftell(fptr); - fseek(fptr, 0, SEEK_SET); - return size; -} - -/** - * \brief dump output tensor. - * - * graph would be destructed if comp_node_seq_record_level == 2; so we should - * store graph info before graph_compile(). - */ -class OutputDumper { - struct DumpInfo { - HostTensorND hv = {}; - std::string var_info; - std::string owner_inputs_info; - size_t id; - }; - SmallVector m_infos; - - size_t m_run_id = 0; - size_t m_bind_id = 0; - const Args& m_env; - -public: - OutputDumper(const Args& env) : m_env{env} { - for (auto&& i : m_env.load_ret.output_var_list) { - auto&& var = i.node(); - DumpInfo info; - info.var_info = cg::dump_var_info({var}); - info.owner_inputs_info = - cg::dump_var_info(var->owner_opr()->input()); - info.id = var->id(); - m_infos.push_back(info); - } - } - - ComputingGraph::Callback bind() { - auto& info = m_infos.at(m_bind_id++); - ComputingGraph::Callback cb = [&info](const DeviceTensorND& dv) { - info.hv.copy_from(dv); - }; - return cb; - } - - void write_to_file() { - if (!m_env.bin_out_dump.empty()) { - for (auto&& info : m_infos) { - auto value = debug::dump_tensor( - info.hv, ssprintf("var=%s owner_opr_inputs=%s", - info.var_info.c_str(), - info.owner_inputs_info.c_str())); - debug::write_to_file( - ssprintf("%s/run%zu-var%zd", m_env.bin_out_dump.c_str(), - m_run_id, info.id) - .c_str(), - value); - } - - } - m_run_id ++; - } -}; - -void format_and_print(const std::string& tablename, const Args& env) { - auto table = mgb::TextTable(tablename); - table.padding(1); - table.align(mgb::TextTable::Align::Mid) - .add("type") - .add("name") - .add("shape") - .eor(); - - for (auto &&i: env.load_ret.tensor_map) { - table.align(mgb::TextTable::Align::Mid) - .add("INPUT") - .add(i.first) - .add(i.second->shape().to_string()) - .eor(); - } - - for (auto&& i : env.load_ret.output_var_list) { - table.align(mgb::TextTable::Align::Mid) - .add("OUTPUT") - .add(i.node()->name()) - .add(i.shape().to_string()) - .eor(); - } - - std::stringstream ss; - ss << table; - printf("%s\n\n", ss.str().c_str()); -} - -void run_test_st(Args &env) { - std::unique_ptr inp_file; - - if (env.share_param_mem) { - FILE *fin = fopen(env.model_path.c_str(), "rb"); - mgb_assert(fin, "failed to open %s: %s", env.model_path.c_str(), - strerror(errno)); - auto size = get_file_size(fin); - void *ptr = malloc(size); - std::shared_ptr buf{ptr, free}; - auto nr = fread(buf.get(), 1, size, fin); - mgb_assert(nr == size); - fclose(fin); - inp_file = serialization::InputFile::make_mem_proxy(buf, size); - } else { - inp_file = serialization::InputFile::make_fs( - env.model_path.c_str()); - } - auto nr_test = read_nr_test(*inp_file); - - auto format = - serialization::GraphLoader::identify_graph_dump_format(*inp_file); - mgb_assert(format.valid(), - "invalid model: unknown model format, please make sure input " - "file is generated by GraphDumper"); - auto loader = - serialization::GraphLoader::make(std::move(inp_file), format.val()); - RealTimer timer; - env.load_ret = loader->load(env.load_config, false); - - // graph is no longer needed; reset so memory can be reclaimed - env.load_config.comp_graph.reset(); - - printf("load model: %.3fms\n", timer.get_msecs_reset()); - - auto& output_var_list = env.load_ret.output_var_list; - mgb::gopt::set_opr_algo_workspace_limit_inplace(output_var_list, - env.workspace_limit); - using S = opr::mixin::AlgoChooserHelper::ExecutionPolicy::Strategy; - S strategy = static_cast(0); - if (env.reproducible) { - strategy = S::REPRODUCIBLE; - } -#if MGB_ENABLE_FASTRUN - if (env.use_full_run) { - strategy = S::PROFILE | strategy; - } else if (env.use_fast_run) { - strategy = S::PROFILE | S::OPTIMIZED | strategy; - } else { - strategy = S::HEURISTIC | strategy; - } -#else - strategy = S::HEURISTIC | strategy; -#endif - mgb::gopt::modify_opr_algo_strategy_inplace(output_var_list, strategy); - if (!env.fast_run_cache_path.empty()) { -#if MGB_ENABLE_FASTRUN - if (!access(env.fast_run_cache_path.c_str(), F_OK)) { -#else - mgb_assert(access(env.fast_run_cache_path.c_str(), F_OK) == 0, - "fast-run cache file can't be accessed"); -#endif - FILE* fin = fopen(env.fast_run_cache_path.c_str(), "rb"); - auto flen = get_file_size(fin); - std::unique_ptr buf{new uint8_t[flen]}; - size_t ret = fread(buf.get(), flen, 1, fin); - MGB_MARK_USED_VAR(ret); - mgb_assert(ret == 1, "read 1 block (got %zu), and block size %zu.", - ret, flen); - fclose(fin); - PersistentCache::set_impl( - std::make_shared(buf.get(), flen)); -#if MGB_ENABLE_FASTRUN - } else { - mgb_assert(env.use_full_run || env.use_fast_run, - "fast-run or fast-run should be enabled"); - PersistentCache::set_impl( - std::make_shared()); - } - if (!env.use_full_run && !env.use_fast_run) -#endif - mgb::gopt::enable_opr_use_profiling_cache_inplace(output_var_list); - } - - // load testcase - decltype(env.load_ret) testcase; - if (nr_test) { - loader = serialization::GraphLoader::make(loader->reset_file(), - loader->format()); - testcase = loader->load(env.load_config, false); - } - - if (env.layout_transform) { - env.load_ret.output_var_list = gopt::layout_transform( - env.load_ret.output_var_list, env.layout_transform_target); - if (!env.layout_transform_dump_path.empty()) { - auto out_file = serialization::OutputFile::make_fs( - env.layout_transform_dump_path.c_str(), 'w'); - if (nr_test) { - const char* magic = "mgbtest0"; - constexpr size_t len = sizeof(magic); - out_file->write(magic, len); - uint32_t nr_inp_tensors = testcase.output_var_list.size(); - out_file->write(&nr_inp_tensors, sizeof(nr_inp_tensors)); - } - auto dumper = serialization::GraphDumper::make(std::move(out_file), - format.val()); - using DumpConfig = serialization::GraphDumper::DumpConfig; - DumpConfig config{1, false, false}; - dumper->dump(env.load_ret.output_var_list, config); - if (nr_test) { - out_file = serialization::OutputFile::make_fs( - env.layout_transform_dump_path.c_str(), 'a'); - auto testdumper = serialization::GraphDumper::make( - std::move(out_file), format.val()); - testdumper->dump(testcase.output_var_list, config); - } - } - } - - // compile function to compute all outputs - ComputingGraph::OutputSpec out_spec; - std::string output_names; - - if (env.display_model_info) { - format_and_print("Original Model Info", env); - } - - OutputDumper output_dumper(env); - for (auto&& i : env.load_ret.output_var_list) { - if (&i != env.load_ret.output_var_list.data()) { - output_names += " "; - } - output_names.append(i.node()->name() + i.shape().to_string()); - ComputingGraph::Callback cb; - if (!env.bin_out_dump.empty()) { - cb = output_dumper.bind(); - } else if (env.copy_to_host) { - HostTensorND val; - cb = [val](const DeviceTensorND& dv) mutable { - val.copy_from(dv); - }; - } - out_spec.emplace_back(i, std::move(cb)); - } - - if (env.disable_assert_throw) { - auto on_opr = [](cg::OperatorNodeBase* opr) { - if (opr->same_type()) { - opr->cast_final().disable_throw_on_error(); - } - }; - cg::DepOprIter iter{on_opr}; - for (auto&& i : out_spec) { - iter.add(i.first.node()->owner_opr()); - } - } - - SymbolVarArray vars; - for (auto i : out_spec) { - vars.push_back(i.first); - } - - auto func = env.load_ret.graph_compile(out_spec); -#ifndef __IN_TEE_ENV__ -#if MGB_ENABLE_JSON - if (!env.static_mem_log_dir_path.empty()) { - func->get_static_memory_alloc_info(env.static_mem_log_dir_path); - } -#endif -#endif - auto warmup = [&]() { - printf("=== prepare: %.3fms; going to warmup\n", - timer.get_msecs_reset()); - for (int run = 0; run < env.nr_warmup; ++run) { - func->execute().wait(); - printf("warmup %d: %.3fms\n", run, timer.get_msecs_reset()); - } - }; - - auto run_iters = [&](uint32_t case_idx) -> float { - double time_sqrsum = 0, time_sum = 0, - min_time = std::numeric_limits::max(), max_time = 0; - for (int run = 0; run < env.nr_run; ++run) { - mgb_log_debug("load_and_run: before running iter %d", run); - timer.reset(); - func->execute(); - mgb_log_debug("load_and_run: before waiting iter %d", run); - auto exec_time = timer.get_msecs(); - func->wait(); - output_dumper.write_to_file(); - auto cur = timer.get_msecs(); - printf("iter %d/%d: %.3fms (exec=%.3f,device=%.3f)\n", run, - env.nr_run, cur, exec_time, - func->get_prev_exec_time() * 1e3); - time_sum += cur; - time_sqrsum += cur * cur; - fflush(stdout); - if (cur < min_time) { - min_time = cur; - } - if (cur > max_time) { - max_time = cur; - } - } - printf("=== finished test #%u: time=%.3fms avg_time=%.3fms " - "sd=%.3fms minmax=%.3f,%.3f\n\n", - case_idx, time_sum, time_sum / env.nr_run, - std::sqrt((time_sqrsum * env.nr_run - time_sum * time_sum) / - (env.nr_run * (env.nr_run - 1))), - min_time, max_time); - return time_sum; - - }; - - if (nr_test) { - // run testcase, generated by dump_with_testcase.py - - std::vector> inp_tensors; - for (auto &&i: env.load_ret.tensor_map) { - inp_tensors.emplace_back(i.first, i.second.get()); - } - std::sort(inp_tensors.begin(), inp_tensors.end()); - - printf("=== going to run %u testcases; output vars: %s\n", nr_test, - output_names.c_str()); - double tot_time = 0; - for (uint32_t i = 0; i < nr_test; ++ i) { - std::shared_ptr c_opr_param; - auto dtype_cpp2c = [](DType dtype) -> MGBDType { - switch (dtype.enumv()) { - case DTypeEnum::Float32: - return MGB_DTYPE_FLOAT32; - case DTypeEnum::Int32: - return MGB_DTYPE_INT32; - case DTypeEnum::Int16: - return MGB_DTYPE_INT16; - case DTypeEnum::Uint8: - return MGB_DTYPE_UINT8; -#if !MEGDNN_DISABLE_FLOAT16 - case DTypeEnum::Float16: - return MGB_DTYPE_FLOAT16; -#endif - default: - mgb_throw(InternalError, - "unsupported dtype for extern C API: %s", - dtype.name()); - } - }; - - auto tensor_shape_to_c = [](const TensorShape& shape, - MGBTensorShape& mgb_shape) { - mgb_assert(shape.ndim <= MGB_TENSOR_MAX_NDIM, - "shape ndim too large: %zu", shape.ndim); - mgb_shape.ndim = shape.ndim; - for (size_t i = 0; i < shape.ndim; ++i) { - mgb_shape.shape[i] = shape[i]; - } - }; - - if (env.c_opr_args.is_run_c_opr_with_param) { - c_opr_param = std::make_shared(); - memset(c_opr_param.get(), 0, sizeof(ExternCOprParam)); - //! we just test input on npu case, do not test output on - //! npu case, so we just init input shape and type - c_opr_param->nr_input = inp_tensors.size(); - c_opr_param->input = (ExternDeviceTensor*)malloc( - sizeof(ExternDeviceTensor) * inp_tensors.size()); - memset(c_opr_param->input, 0, - sizeof(ExternDeviceTensor) * inp_tensors.size()); - //! init input ExternDeviceTensor shape and dtype - for (size_t input_index = 0; input_index < inp_tensors.size(); - input_index++) { - auto& mgb_tensor_layout = - c_opr_param->input[input_index].layout; - auto host_tensor_nd_p = inp_tensors[input_index].second; - mgb_tensor_layout.dtype = - dtype_cpp2c(host_tensor_nd_p->dtype()); - tensor_shape_to_c(inp_tensors[input_index].second->shape(), - mgb_tensor_layout.shape); - } - c_opr_param->nr_output = 0; - //! now call copr_param_device_ptr_malloc to malloc - //! device_ptr - env.c_opr_args.copr_param_device_ptr_malloc(c_opr_param.get()); - } - - mgb_assert(testcase.output_var_list.size() == inp_tensors.size()); - for (size_t i = 0; i < inp_tensors.size(); ++ i) { - auto &&opr = testcase.output_var_list[i].node()->owner_opr()-> - cast_final_safe(); - if (env.c_opr_args.is_run_c_opr_with_param) { - //! now call copr_param_device_ptr_h2d to fill data - env.c_opr_args.copr_param_device_ptr_h2d( - c_opr_param.get(), opr.dev_data()->raw_ptr(), i); - } else { - inp_tensors[i].second->copy_from( - HostTensorND::make_proxy(*opr.dev_data())); - } - } - //! now config c opr dynamic param - if (env.c_opr_args.is_run_c_opr_with_param) { - config_extern_c_opr_dynamic_param(func, c_opr_param); - } - - if (!i) { - warmup(); - } - - timer.reset(); - printf("=== going to run test #%u for %d times\n", i, env.nr_run); - if (!env.nr_run) { - continue; - } - tot_time += run_iters(i); - - //! now free c opr device_ptr - if (env.c_opr_args.is_run_c_opr_with_param) { - env.c_opr_args.copr_param_device_ptr_free(c_opr_param.get()); - free(c_opr_param->input); - } - } - - printf("=== total time: %.3fms\n", tot_time); - } else if (not env.data_files.empty()) { - mgb_assert(!env.c_opr_args.is_run_c_opr_with_param, - "run c opr with param only support dump_with_testcase!!"); - auto& tensormap = env.load_ret.tensor_map; - - DataParser parser; - for (auto path : env.data_files) { - parser.feed(path); - } - auto inputs = parser.inputs; - if (inputs.size() > 1) { - for (auto& i : inputs) { - mgb_assert(tensormap.find(i.first) != tensormap.end()); - - auto& in = tensormap.find(i.first)->second; - in->copy_from(i.second); - } - } else { - auto& in = tensormap.begin()->second; - in->copy_from(inputs.begin()->second); - } - - warmup(); - timer.reset(); - printf("=== going to run input for %d times\n", env.nr_run); - run_iters(0); - } else { - mgb_assert(!env.c_opr_args.is_run_c_opr_with_param, - "run c opr with param only support dump_with_testcase!!"); - // run speed test for a raw mgb graph - mgb_assert(env.load_ret.tensor_map.empty(), - "model should not require input values; input vars should be " - "replaced by SharedDeviceTensor " - "(i.e. megskull.opr.ParamProvider)"); - - warmup(); - timer.reset(); - printf("=== going to run for %d times; output vars: %s\n", - env.nr_run, output_names.c_str()); - for (int i = 0; i < env.nr_run; ++ i) { - mgb_log_debug("load_and_run: before benchmark iter %d", i); - auto start = timer.get_msecs(); - func->execute().wait(); - output_dumper.write_to_file(); - printf("=== finished run #%d: time=%.3fms\n", i, - timer.get_msecs() - start); - fflush(stdout); - } - printf("avg time: %.3fms\n", timer.get_msecs() / env.nr_run); - } - -#if MGB_ENABLE_JSON - if (env.profiler) { - env.profiler->to_json_full(func.get())->writeto_fpath( - env.profiler_output); - mgb_log("profiling result written to %s", env.profiler_output.c_str()); - } -#endif -#if MGB_ENABLE_FASTRUN - if (!env.fast_run_cache_path.empty()) { - static_cast(PersistentCache::inst()) - .dump_cache(env.fast_run_cache_path.c_str()); - } -#endif -#if MGB_ENABLE_TENSOR_RT - if (TensorRTEngineCache::enable_engine_cache()) { - TensorRTEngineCache::inst().dump_cache(); - } -#endif - - if (env.display_model_info) { - format_and_print("Runtime Model Info", env); - } -} - -} // anonymous namespace - -int mgb_load_and_run_main(int argc, char** argv) { - { - auto v0 = get_version(); - auto v1 = megdnn::get_version(); - printf("mgb load-and-run: using MegBrain " - "%d.%d.%d(%d) and MegDNN %d.%d.%d\n", - v0.major, v0.minor, v0.patch, v0.is_dev, v1.major, v1.minor, - v1.patch); - } - auto env = Args::from_argv(argc, argv); - - if (env.c_opr_args.is_run_c_opr_with_param) - mgb_assert(env.c_opr_args.is_run_c_opr && - env.c_opr_args.copr_param_device_ptr_malloc && - env.c_opr_args.copr_param_device_ptr_free && - env.c_opr_args.copr_param_device_ptr_h2d, - "--c-opr-lib-with-param need config with --c-opr-lib, also " - "extern c opr loader need implemente " - "copr_param_device_ptr_malloc, copr_param_device_ptr_free " - "and copr_param_device_ptr_h2d symbols"); - - if (env.args_parse_ret != 0) { - return env.args_parse_ret; - } - - if (env.nr_thread == 1) { - run_test_st(env); - } else { -#if MGB_HAVE_THREAD - mgb_log_warn("use %d threads", env.nr_thread); - std::vector threads; - auto run = [argc, argv]() { - auto env = Args::from_argv(argc, argv); - run_test_st(env); - }; - - for (int i = 0; i < env.nr_thread; ++i) { - threads.emplace_back(run); - } - - for (auto&& i : threads) { - i.join(); - } -#else - mgb_log_error("%d threads requested, but load-and-run was compiled " - "without thread support."); -#endif - } - - return 0; -} - -Args Args::from_argv(int argc, char **argv) { - Args ret; - if (argc < 2) { - printf("usage: %s [options...]\nWhere options are:%s", - argv[0], OPTIONS_DESC); - ret.args_parse_ret = -1; - return ret; - } - set_log_level(LogLevel::WARN); - ret.model_path = argv[1]; - ret.load_config.comp_graph = ComputingGraph::make(); - auto &&graph_opt = ret.load_config.comp_graph->options(); - graph_opt.graph_opt_level = 0; - - for (int i = 2; i < argc; ++ i) { - if (!strcmp(argv[i], "--cpu")) { - mgb_log_warn("use cpu mode"); - ret.load_config.comp_node_mapper = [](CompNode::Locator &loc) { - loc.type = CompNode::DeviceType::CPU; - }; - continue; - } - if (!strcmp(argv[i], "--cpu-default")) { - mgb_log_warn("use cpu:default mode"); - ret.load_config.comp_node_mapper = [](CompNode::Locator &loc) { - loc.type = CompNode::DeviceType::CPU; - loc.device = CompNode::Locator::DEVICE_CPU_DEFAULT; - }; - continue; - } - if (!strcmp(argv[i], "--multithread")) { - mgb_log_warn("use multithread mode"); - ++ i; - ret.multithread_number = std::stoi(argv[i]); - ret.load_config.comp_node_mapper = - [nr_threads = - ret.multithread_number](CompNode::Locator& loc) { - loc.type = CompNode::DeviceType::MULTITHREAD; - loc.device = 0; - loc.stream = nr_threads; - }; - continue; - } - if (!strcmp(argv[i], "--multithread-default")) { - mgb_log_warn("use multithread:default mode"); - ++i; - ret.multithread_number = std::stoi(argv[i]); - ret.load_config.comp_node_mapper = [nr_threads = - ret.multithread_number]( - CompNode::Locator& loc) { - loc.type = CompNode::DeviceType::MULTITHREAD; - loc.device = CompNode::Locator::DEVICE_MULTITHREAD_DEFAULT; - loc.nr_threads = nr_threads; - }; - continue; - } - if (!strcmp(argv[i], "--multi-thread-core-ids")) { - ++i; - std::string core_id_string = argv[i]; - std::stringstream input_stringstream(core_id_string); - std::string id; - size_t nr_threads = 0; - std::vector core_ids; - mgb_log_warn("multi thread core ids: %s", core_id_string.c_str()); - while(getline(input_stringstream, id, ',')) { - nr_threads++; - core_ids.push_back(atoi(id.c_str())); - } - mgb_assert(ret.multithread_number > 0 && - ret.load_config.comp_node_mapper, - "the core id should set behind the --multithread param"); - mgb_assert(static_cast(ret.multithread_number) == - core_ids.size(), - "the core id should equal to the multi thread number"); - auto affinity_cb = [core_ids](int thread_id) { - mgb::sys::set_cpu_affinity({core_ids[thread_id]}); - }; - CompNode::Locator loc; - ret.load_config.comp_node_mapper(loc); - mgb_assert(loc.type == CompNode::DeviceType::MULTITHREAD, - "core id only set on multithread compnode"); - auto cn = CompNode::load(loc); - CompNodeEnv::from_comp_node(cn).cpu_env().set_affinity(affinity_cb); - continue; - } -#if MGB_ENABLE_TENSOR_RT - if (!strcmp(argv[i], "--tensorrt")) { - mgb_log_warn("use tensorrt mode"); - graph_opt.graph_opt.tensorrt = true; - continue; - } - if (!strcmp(argv[i], "--tensorrt-cache")) { - ++i; - mgb_assert(i < argc, "value not given for --tensorrt-cache"); - char* tensorrt_cache_path = argv[i]; - mgb_log_warn("use tensorrt cache: %s", tensorrt_cache_path); - TensorRTEngineCache::enable_engine_cache(true); - TensorRTEngineCache::set_impl( - std::make_shared( - tensorrt_cache_path)); - continue; - } -#endif - -#define cb(_layout) \ - if (!strcmp(argv[i], "--enable-" #_layout)) { \ - mgb_log_warn("enable " #_layout " optimization"); \ - graph_opt.graph_opt.enable_##_layout(); \ - continue; \ - } - - cb(nchw4); - cb(chwn4); - cb(nchw44); - cb(nchw88); - cb(nchw32); - cb(nhwcd4); - cb(nchw64); -#undef cb - if (!strcmp(argv[i], "--enable-nchw44-dot")) { - mgb_log_warn("enable-nchw44-dot optimization"); - graph_opt.graph_opt.enable_nchw44_dot(); - continue; - } - if (!strcmp(argv[i], "--enable-fuse-preprocess")) { - mgb_log_warn("enable-fuse-preprocess optimization"); - graph_opt.graph_opt.enable_fuse_preprocess(); - continue; - } - if (!strcmp(argv[i], "--enable-fuse-conv-bias-nonlinearity")) { - mgb_log_warn("enable fuse-conv-bias-nonlinearity optimization"); - graph_opt.graph_opt.enable_fuse_conv_bias_nonlinearity(); - continue; - } - if (!strcmp(argv[i], "--enable-fuse-conv-bias-with-z")) { - mgb_log_warn("enable fuse_conv_bias_with_z optimization"); - graph_opt.graph_opt.enable_fuse_conv_bias_with_z(); - continue; - } -#if MGB_ENABLE_JSON - if (!strcmp(argv[i], "--profile") || - !strcmp(argv[i], "--profile-host")) { - if (!strcmp(argv[i], "--profile")) { - mgb_log_warn("enable profiling"); - } else { - mgb_log_warn("enable profiling for host"); - } - ++i; - mgb_assert(i < argc, "output file not given for --profile"); - ret.profiler = std::make_unique( - ret.load_config.comp_graph.get()); - ret.profiler_output = argv[i]; - continue; - } -#endif - if (!strcmp(argv[i], "--input")) { - ++i; - mgb_assert(i < argc, "input file not given for --input"); - - size_t start = 0; - std::string cmd = argv[i]; - - while (true) { - auto end = cmd.find(";", start); - if (end == std::string::npos) { - ret.data_files.emplace_back(cmd.substr(start)); - break; - } - std::string substr = cmd.substr(start, end - start); - ret.data_files.emplace_back(substr); - start = end + 1; - } - continue; - } - if (!strcmp(argv[i], "--model-info")) { - ++i; - ret.display_model_info = true; - continue; - } - if (!strcmp(argv[i], "--io-dump")) { - mgb_log_warn("enable opr io dump"); - ++ i; - mgb_assert(i < argc, "output file not given for --io-dump"); - auto iodump = std::make_unique( - ret.load_config.comp_graph.get(), argv[i]); - iodump->print_addr(false); - ret.iodump = std::move(iodump); - continue; - } - if (!strcmp(argv[i], "--io-dump-stdout")) { - mgb_log_warn("enable opr io dump to stdout"); - std::shared_ptr sp(stdout, [](FILE*){}); - auto iodump = std::make_unique( - ret.load_config.comp_graph.get(), sp); - iodump->print_addr(false); - ret.iodump = std::move(iodump); - continue; - } - if (!strcmp(argv[i], "--io-dump-stderr")) { - mgb_log_warn("enable opr io dump to stderr"); - std::shared_ptr sp(stderr, [](FILE*){}); - auto iodump = std::make_unique( - ret.load_config.comp_graph.get(), sp); - iodump->print_addr(false); - ret.iodump = std::move(iodump); - continue; - } - if (!strcmp(argv[i], "--bin-io-dump")) { - mgb_log_warn("enable opr binary io dump"); - ++ i; - mgb_assert(i < argc, - "output directory not given for --bin-io-dump"); - ret.iodump = std::make_unique( - ret.load_config.comp_graph.get(), argv[i]); - continue; - } - if (!strcmp(argv[i], "--bin-out-dump")) { - ++ i; - mgb_assert(i < argc, - "output directory not given for --bin-out-dump"); - ret.bin_out_dump = argv[i]; - continue; - } - if (!strcmp(argv[i], "--iter")) { - ++ i; - mgb_assert(i < argc, "value not given for --iter"); - ret.nr_run = std::stoi(argv[i]); - mgb_assert(ret.nr_run >= 0); - continue; - } - if (!strcmp(argv[i], "--warmup-iter")) { - ++ i; - mgb_assert(i < argc, "value not given for --warmup-iter"); - ret.nr_warmup = std::stoi(argv[i]); - mgb_assert(ret.nr_warmup >= 0); - continue; - } - if (!strcmp(argv[i], "--range")) { - ++ i; - mgb_assert(i < argc, "value not given for --range"); - auto range = std::atof(argv[i]); - mgb_assert(range > 0); - ret.num_range_checker = std::make_unique( - ret.load_config.comp_graph.get(), range); - continue; - } - if (!strcmp(argv[i], "--check-dispatch")) { - ret.cpu_dispatch_checker = - std::make_unique( - ret.load_config.comp_graph.get()); - continue; - } - if (!strcmp(argv[i], "--disable-mem-opt")) { - graph_opt.seq_opt.enable_mem_reuse_alloc = false; - graph_opt.seq_opt.enable_mem_plan_opt = false; - continue; - } - if (!strcmp(argv[i], "--copy-to-host")) { - ret.copy_to_host = true; - continue; - } - if (!strcmp(argv[i], "--verbose")) { - graph_opt.log_level = 2; - set_log_level(LogLevel::DEBUG); - continue; - } - if (!strcmp(argv[i], "--check-var-value")) { - ++ i; - mgb_assert(i < argc, "value not given for --check-var-value"); - std::string arg(argv[i]); - auto sep = arg.find(':'); - size_t switch_interval, start = 0; - if (sep != std::string::npos) { - switch_interval = std::stoul(arg.substr(0, sep)); - start = std::stoul(arg.substr(sep + 1)); - } else { - switch_interval = std::stoul(arg); - } - ret.var_value_checker = std::make_unique( - ret.load_config.comp_graph.get(), switch_interval, start); - continue; - } - if (!strcmp(argv[i], "--no-sanity-check")) { - graph_opt.var_sanity_check_first_run = false; - continue; - } - if (!strcmp(argv[i], "--fake-first")) { - graph_opt.fake_next_exec = true; - continue; - } - if (!strcmp(argv[i], "--record-comp-seq")) { - graph_opt.comp_node_seq_record_level = 1; - continue; - } - if (!strcmp(argv[i], "--record-comp-seq2")) { - graph_opt.comp_node_seq_record_level = 2; - continue; - } -#ifndef __IN_TEE_ENV__ -#if MGB_ENABLE_JSON - if (!strcmp(argv[i], "--get-static-mem-info")) { - ++i; - mgb_assert(i < argc, "value not given for --get-static-mem-info"); - ret.static_mem_log_dir_path = argv[i]; - continue; - } -#endif -#endif -#if MGB_ENABLE_FASTRUN - if (!strcmp(argv[i], "--fast-run")) { - ret.use_fast_run = true; - continue; - } - if (!strcmp(argv[i], "--full-run")) { - ret.use_full_run = true; - continue; - } -#endif - if (!strcmp(argv[i], "--fast-run-algo-policy")) { - ++i; - ret.fast_run_cache_path = argv[i]; - continue; - } - if (!strcmp(argv[i], "--fast-run-shared-batch-size")) { - ++i; - mgb_assert(i < argc, - "value not given for --fast-run-shared-batch-size"); - int32_t batch_size = std::stoi(argv[i]); - mgb_assert(batch_size >= 0); - graph_opt.fast_run_config.shared_batch_size = batch_size; - continue; - } - if (!strcmp(argv[i], "--binary-equal-between-batch")) { - graph_opt.fast_run_config.binary_equal_between_batch = true; - ret.reproducible = true; - continue; - } - if (!strcmp(argv[i], "--reproducible")) { - ret.reproducible = true; - continue; - } - if (!strcmp(argv[i], "--const-shape")) { - ret.load_config.const_var_shape = true; - continue; - } - if (!strcmp(argv[i], "--share-param-mem")) { - ret.share_param_mem = true; - continue; - } - if (!strcmp(argv[i], "--disable-assert-throw")) { - ret.disable_assert_throw = true; - continue; - } - if (!strcmp(argv[i], "--workspace-limit")) { - ++i; - ret.workspace_limit = std::stoll(argv[i]); - continue; - } -#if __linux__ || __unix__ - if (!strcmp(argv[i], "--wait-gdb")) { - printf("wait for gdb attach (pid=%d): ", getpid()); - getchar(); - continue; - } - if (!strcmp(argv[i], "--c-opr-lib")) { - ++ i; - ret.c_opr_args.is_run_c_opr = true; - mgb_assert(i < argc, "value not given for --c-opr-lib"); - auto handle = dlopen(argv[i], RTLD_LAZY); - mgb_assert(handle, "failed to open c opr lib %s: %s", - argv[i], dlerror()); - const char* entry = MGB_C_OPR_INIT_FUNC_STR; - auto func = dlsym(handle, entry); - mgb_assert(func, "can not resolve %s: %s", entry, dlerror()); - typedef void (*entry_f_t)(void*); - reinterpret_cast(func)( - reinterpret_cast( - &mgb_get_extern_c_opr_api_versioned)); - printf("loaded C opr library: %s\n", argv[i]); - - entry = "copr_param_device_ptr_malloc"; - func = dlsym(handle, entry); - if (func) { - printf("get %s from: %s\n", entry, argv[i]); - ret.c_opr_args.copr_param_device_ptr_malloc = - reinterpret_cast( - func); - } - entry = "copr_param_device_ptr_free"; - func = dlsym(handle, entry); - if (func) { - printf("get %s from: %s\n", entry, argv[i]); - ret.c_opr_args.copr_param_device_ptr_free = - reinterpret_cast( - func); - } - entry = "copr_param_device_ptr_h2d"; - func = dlsym(handle, entry); - if (func) { - printf("get %s from: %s\n", entry, argv[i]); - ret.c_opr_args.copr_param_device_ptr_h2d = - reinterpret_cast( - func); - } - - continue; - } - if (!strcmp(argv[i], "--c-opr-lib-with-param")) { - ret.c_opr_args.is_run_c_opr_with_param = true; - continue; - } -#endif - if (!strcmp(argv[i], "--thread")) { - ++ i; - mgb_assert(i < argc, "value not given for --thread"); - ret.nr_thread = std::stoi(argv[i]); - continue; - } - if (!strcmp(argv[i], "--enable-jit")) { - graph_opt.graph_opt.jit = 1; - continue; - } - if (!strcmp(argv[i], "--weight-preprocess")) { - mgb_log_warn("enable weight-preprocess optimization"); - graph_opt.graph_opt.enable_weight_preprocess(); - continue; - } - if (!strcmp(argv[i], "--layout-transform")) { - ret.layout_transform = true; - ++i; - if (i >= argc) { - --i; - continue; - } - - using Target = gopt::GraphTuningOptions::Target; - if (!strcmp(argv[i], "cuda")) { - ret.layout_transform_target = Target::CUDA; - } else if (!strcmp(argv[i], "x86")) { - ret.layout_transform_target = Target::X86; - } else if (!strcmp(argv[i], "arm")) { - ret.layout_transform_target = Target::ARM; - } else if (!strcmp(argv[i], "opencl")) { - ret.layout_transform_target = Target::OPENCL; - } else if (!strncmp(argv[i], "--", 2)) { - --i; - } else { - mgb_assert(false, - "unsupported target(got:%s) for global layout " - "transform", - argv[i]); - } - - continue; - } - - if (!strcmp(argv[i], "--layout-transform-dump")) { - ++i; - mgb_assert(i < argc, - "dump path not given for --layout-transform-dump"); - mgb_assert(strncmp(argv[i], "--", 2), - "dump path not given for --layout-transform-dump"); - ret.layout_transform_dump_path = argv[i]; - continue; - } - - fprintf(stderr, "invalid arg: %s\n", argv[i]); - ret.args_parse_ret = -1; - return ret; - } - -#if MGB_ENABLE_FASTRUN - if (graph_opt.fast_run_config.shared_batch_size) { - mgb_assert(ret.use_fast_run || ret.use_full_run || - !ret.fast_run_cache_path.empty(), - "--fast-run-shared-batch-size should be used with " - "--fast-run/--full-run/--fast-run-algo-policy"); - } -#endif - return ret; -} - -// vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}} diff --git a/sdk/load-and-run/src/mgblar.h b/sdk/load-and-run/src/mgblar.h deleted file mode 100644 index 2fdff00d..00000000 --- a/sdk/load-and-run/src/mgblar.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * \file sdk/load-and-run/src/mgblar.h - * MegEngine is Licensed under the Apache License, Version 2.0 (the "License") - * - * Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - int mgb_load_and_run_main(int argc, char **argv); -#ifdef __cplusplus -} -#endif - -// vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}} diff --git a/sdk/load-and-run/src/npy.h b/sdk/load-and-run/src/npy.h deleted file mode 100644 index c04cc1cb..00000000 --- a/sdk/load-and-run/src/npy.h +++ /dev/null @@ -1,627 +0,0 @@ -/* - Copyright 2017 Leon Merten Lohse - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -#ifndef NPY_H -#define NPY_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace npy { - -/* Compile-time test for byte order. - If your compiler does not define these per default, you may want to define - one of these constants manually. - Defaults to little endian order. */ -#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \ - defined(__BIG_ENDIAN__) || defined(__ARMEB__) || \ - defined(__THUMBEB__) || defined(__AARCH64EB__) || defined(_MIBSEB) || \ - defined(__MIBSEB) || defined(__MIBSEB__) -const bool big_endian = true; -#else -const bool big_endian = false; -#endif - -const char magic_string[] = "\x93NUMPY"; -const size_t magic_string_length = 6; - -const char little_endian_char = '<'; -const char big_endian_char = '>'; -const char no_endian_char = '|'; - -constexpr char host_endian_char = - (big_endian ? big_endian_char : little_endian_char); - -/* npy array length */ -typedef unsigned long int ndarray_len_t; - -inline void write_magic(std::ostream& ostream, unsigned char v_major = 1, - unsigned char v_minor = 0) { - ostream.write(magic_string, magic_string_length); - ostream.put(v_major); - ostream.put(v_minor); -} - -inline void read_magic(std::istream& istream, unsigned char& v_major, - unsigned char& v_minor) { - char buf[magic_string_length + 2]; - istream.read(buf, magic_string_length + 2); - - if (!istream) { - fprintf(stderr, "io error: failed reading file"); - } - - if (0 != std::memcmp(buf, magic_string, magic_string_length)) { - fprintf(stderr, "this file does not have a valid npy format."); - } - - v_major = buf[magic_string_length]; - v_minor = buf[magic_string_length + 1]; -} - -// typestring magic -struct Typestring { -private: - char c_endian; - char c_type; - int len; - -public: - inline std::string str() { - const size_t max_buflen = 16; - char buf[max_buflen]; - std::sprintf(buf, "%c%c%u", c_endian, c_type, len); - return std::string(buf); - } - - Typestring(const std::vector&) - : c_endian{host_endian_char}, c_type{'f'}, len{sizeof(float)} {} - Typestring(const std::vector&) - : c_endian{host_endian_char}, c_type{'f'}, len{sizeof(double)} {} - Typestring(const std::vector&) - : c_endian{host_endian_char}, - c_type{'f'}, - len{sizeof(long double)} {} - - Typestring(const std::vector&) - : c_endian{no_endian_char}, c_type{'i'}, len{sizeof(char)} {} - Typestring(const std::vector&) - : c_endian{host_endian_char}, c_type{'i'}, len{sizeof(short)} {} - Typestring(const std::vector&) - : c_endian{host_endian_char}, c_type{'i'}, len{sizeof(int)} {} - Typestring(const std::vector&) - : c_endian{host_endian_char}, c_type{'i'}, len{sizeof(long)} {} - Typestring(const std::vector&) - : c_endian{host_endian_char}, c_type{'i'}, len{sizeof(long long)} {} - - Typestring(const std::vector&) - : c_endian{no_endian_char}, - c_type{'u'}, - len{sizeof(unsigned char)} {} - Typestring(const std::vector&) - : c_endian{host_endian_char}, - c_type{'u'}, - len{sizeof(unsigned short)} {} - Typestring(const std::vector&) - : c_endian{host_endian_char}, - c_type{'u'}, - len{sizeof(unsigned int)} {} - Typestring(const std::vector&) - : c_endian{host_endian_char}, - c_type{'u'}, - len{sizeof(unsigned long)} {} - Typestring(const std::vector&) - : c_endian{host_endian_char}, - c_type{'u'}, - len{sizeof(unsigned long long)} {} - - Typestring(const std::vector>&) - : c_endian{host_endian_char}, - c_type{'c'}, - len{sizeof(std::complex)} {} - Typestring(const std::vector>&) - : c_endian{host_endian_char}, - c_type{'c'}, - len{sizeof(std::complex)} {} - Typestring(const std::vector>&) - : c_endian{host_endian_char}, - c_type{'c'}, - len{sizeof(std::complex)} {} -}; - -inline void parse_typestring(std::string typestring) { - std::regex re("'([<>|])([ifuc])(\\d+)'"); - std::smatch sm; - - std::regex_match(typestring, sm, re); - - if (sm.size() != 4) { - fprintf(stderr, "invalid typestring"); - } -} - -namespace pyparse { - -/** - Removes leading and trailing whitespaces - */ -inline std::string trim(const std::string& str) { - const std::string whitespace = " \t"; - auto begin = str.find_first_not_of(whitespace); - - if (begin == std::string::npos) - return ""; - - auto end = str.find_last_not_of(whitespace); - - return str.substr(begin, end - begin + 1); -} - -inline std::string get_value_from_map(const std::string& mapstr) { - size_t sep_pos = mapstr.find_first_of(":"); - if (sep_pos == std::string::npos) - return ""; - - std::string tmp = mapstr.substr(sep_pos + 1); - return trim(tmp); -} - -/** - Parses the string representation of a Python dict - - The keys need to be known and may not appear anywhere else in the data. - */ -inline std::unordered_map parse_dict( - std::string in, std::vector& keys) { - std::unordered_map map; - - if (keys.size() == 0) - return map; - - in = trim(in); - - // unwrap dictionary - if ((in.front() == '{') && (in.back() == '}')) - in = in.substr(1, in.length() - 2); - else { - fprintf(stderr, "Not a Python dictionary."); - } - - std::vector> positions; - - for (auto const& value : keys) { - size_t pos = in.find("'" + value + "'"); - - if (pos == std::string::npos) { - fprintf(stderr, "Missing %s key.", value.c_str()); - } - - std::pair position_pair{pos, value}; - positions.push_back(position_pair); - } - - // sort by position in dict - std::sort(positions.begin(), positions.end()); - - for (size_t i = 0; i < positions.size(); ++i) { - std::string raw_value; - size_t begin{positions[i].first}; - size_t end{std::string::npos}; - - std::string key = positions[i].second; - - if (i + 1 < positions.size()) - end = positions[i + 1].first; - - raw_value = in.substr(begin, end - begin); - - raw_value = trim(raw_value); - - if (raw_value.back() == ',') - raw_value.pop_back(); - - map[key] = get_value_from_map(raw_value); - } - - return map; -} - -/** - Parses the string representation of a Python boolean - */ -inline bool parse_bool(const std::string& in) { - if (in == "True") - return true; - if (in == "False") - return false; - - fprintf(stderr, "Invalid python boolan."); - return false; -} - -/** - Parses the string representation of a Python str - */ -inline std::string parse_str(const std::string& in) { - if ((in.front() == '\'') && (in.back() == '\'')) - return in.substr(1, in.length() - 2); - - fprintf(stderr, "Invalid python string."); - return ""; -} - -/** - Parses the string represenatation of a Python tuple into a vector of its items - */ -inline std::vector parse_tuple(std::string in) { - std::vector v; - const char seperator = ','; - - in = trim(in); - - if ((in.front() == '(') && (in.back() == ')')) - in = in.substr(1, in.length() - 2); - else { - fprintf(stderr, "Invalid Python tuple."); - } - - std::istringstream iss(in); - - for (std::string token; std::getline(iss, token, seperator);) { - v.push_back(token); - } - - return v; -} - -template -inline std::string write_tuple(const std::vector& v) { - if (v.size() == 0) - return ""; - - std::ostringstream ss; - - if (v.size() == 1) { - ss << "(" << v.front() << ",)"; - } else { - const std::string delimiter = ", "; - // v.size() > 1 - ss << "("; - std::copy(v.begin(), v.end() - 1, - std::ostream_iterator(ss, delimiter.c_str())); - ss << v.back(); - ss << ")"; - } - - return ss.str(); -} - -inline std::string write_boolean(bool b) { - if (b) - return "True"; - else - return "False"; -} - -} // namespace pyparse - -inline void parse_header(std::string header, std::string& descr) { - /* - The first 6 bytes are a magic string: exactly "x93NUMPY". - The next 1 byte is an unsigned byte: the major version number of the file - format, e.g. x01. The next 1 byte is an unsigned byte: the minor version - number of the file format, e.g. x00. Note: the version of the file format - is not tied to the version of the numpy package. The next 2 bytes form a - little-endian unsigned short int: the length of the header data - HEADER_LEN. The next HEADER_LEN bytes form the header data describing the - array's format. It is an ASCII string which contains a Python literal - expression of a dictionary. It is terminated by a newline ('n') and - padded with spaces - ('x20') to make the total length of the magic string + 4 + HEADER_LEN be - evenly divisible by 16 for alignment purposes. The dictionary contains - three keys: - - "descr" : dtype.descr - An object that can be passed as an argument to the numpy.dtype() - constructor to create the array's dtype. For repeatability and - readability, this dictionary is formatted using pprint.pformat() so the - keys are in alphabetic order. - */ - - // remove trailing newline - if (header.back() != '\n') - fprintf(stderr, "invalid header"); - header.pop_back(); - - // parse the dictionary - std::vector keys{"descr"}; - auto dict_map = npy::pyparse::parse_dict(header, keys); - - if (dict_map.size() == 0) - fprintf(stderr, "invalid dictionary in header"); - - std::string descr_s = dict_map["descr"]; - parse_typestring(descr_s); - // remove - descr = npy::pyparse::parse_str(descr_s); - return; -} - -inline void parse_header(std::string header, std::string& descr, - bool& fortran_order, - std::vector& shape) { - /* - The first 6 bytes are a magic string: exactly "x93NUMPY". - The next 1 byte is an unsigned byte: the major version number of the file - format, e.g. x01. The next 1 byte is an unsigned byte: the minor version - number of the file format, e.g. x00. Note: the version of the file format - is not tied to the version of the numpy package. The next 2 bytes form a - little-endian unsigned short int: the length of the header data - HEADER_LEN. The next HEADER_LEN bytes form the header data describing the - array's format. It is an ASCII string which contains a Python literal - expression of a dictionary. It is terminated by a newline ('n') and - padded with spaces - ('x20') to make the total length of the magic string + 4 + HEADER_LEN be - evenly divisible by 16 for alignment purposes. The dictionary contains - three keys: - - "descr" : dtype.descr - An object that can be passed as an argument to the numpy.dtype() - constructor to create the array's dtype. "fortran_order" : bool Whether - the array data is Fortran-contiguous or not. Since Fortran-contiguous - arrays are a common form of non-C-contiguity, we allow them to be written - directly to disk for efficiency. "shape" : tuple of int The shape of the - array. For repeatability and readability, this dictionary is formatted - using pprint.pformat() so the keys are in alphabetic order. - */ - - // remove trailing newline - if (header.back() != '\n') - fprintf(stderr, "invalid header"); - header.pop_back(); - - // parse the dictionary - std::vector keys{"descr", "fortran_order", "shape"}; - auto dict_map = npy::pyparse::parse_dict(header, keys); - - if (dict_map.size() == 0) - fprintf(stderr, "invalid dictionary in header"); - - std::string descr_s = dict_map["descr"]; - std::string fortran_s = dict_map["fortran_order"]; - std::string shape_s = dict_map["shape"]; - - // TODO: extract info from typestring - parse_typestring(descr_s); - // remove - descr = npy::pyparse::parse_str(descr_s); - - // convert literal Python bool to C++ bool - fortran_order = npy::pyparse::parse_bool(fortran_s); - - // parse the shape tuple - auto shape_v = npy::pyparse::parse_tuple(shape_s); - if (shape_v.size() == 0) - fprintf(stderr, "invalid shape tuple in header"); - - for (auto item : shape_v) { - ndarray_len_t dim = static_cast(std::stoul(item)); - shape.push_back(dim); - } -} - -inline std::string write_header_dict(const std::string& descr, - bool fortran_order, - const std::vector& shape) { - std::string s_fortran_order = npy::pyparse::write_boolean(fortran_order); - std::string shape_s = npy::pyparse::write_tuple(shape); - - return "{'descr': '" + descr + "', 'fortran_order': " + s_fortran_order + - ", 'shape': " + shape_s + ", }"; -} - -inline void write_header(std::ostream& out, const std::string& descr, - bool fortran_order, - const std::vector& shape_v) { - std::string header_dict = write_header_dict(descr, fortran_order, shape_v); - - size_t length = magic_string_length + 2 + 2 + header_dict.length() + 1; - - unsigned char version[2] = {1, 0}; - if (length >= 255 * 255) { - length = magic_string_length + 2 + 4 + header_dict.length() + 1; - version[0] = 2; - version[1] = 0; - } - size_t padding_len = 16 - length % 16; - std::string padding(padding_len, ' '); - - // write magic - write_magic(out, version[0], version[1]); - - // write header length - if (version[0] == 1 && version[1] == 0) { - char header_len_le16[2]; - uint16_t header_len = static_cast(header_dict.length() + - padding.length() + 1); - - header_len_le16[0] = (header_len >> 0) & 0xff; - header_len_le16[1] = (header_len >> 8) & 0xff; - out.write(reinterpret_cast(header_len_le16), 2); - } else { - char header_len_le32[4]; - uint32_t header_len = static_cast(header_dict.length() + - padding.length() + 1); - - header_len_le32[0] = (header_len >> 0) & 0xff; - header_len_le32[1] = (header_len >> 8) & 0xff; - header_len_le32[2] = (header_len >> 16) & 0xff; - header_len_le32[3] = (header_len >> 24) & 0xff; - out.write(reinterpret_cast(header_len_le32), 4); - } - - out << header_dict << padding << '\n'; -} - -inline std::string read_header(std::istream& istream) { - // check magic bytes an version number - unsigned char v_major, v_minor; - read_magic(istream, v_major, v_minor); - - uint32_t header_length = 0; - if (v_major == 1 && v_minor == 0) { - char header_len_le16[2]; - istream.read(header_len_le16, 2); - header_length = (header_len_le16[0] << 0) | (header_len_le16[1] << 8); - - if ((magic_string_length + 2 + 2 + header_length) % 16 != 0) { - // TODO: display warning - } - } else if (v_major == 2 && v_minor == 0) { - char header_len_le32[4]; - istream.read(header_len_le32, 4); - - header_length = (header_len_le32[0] << 0) | (header_len_le32[1] << 8) | - (header_len_le32[2] << 16) | (header_len_le32[3] << 24); - - if ((magic_string_length + 2 + 4 + header_length) % 16 != 0) { - // TODO: display warning - } - } else { - fprintf(stderr, "unsupported file format version"); - } - - auto buf_v = std::vector(); - buf_v.reserve(header_length); - istream.read(buf_v.data(), header_length); - std::string header(buf_v.data(), header_length); - - return header; -} - -inline ndarray_len_t comp_size(const std::vector& shape) { - ndarray_len_t size = 1; - for (ndarray_len_t i : shape) - size *= i; - - return size; -} - -template -inline void SaveArrayAsNumpy(const std::string& filename, bool fortran_order, - unsigned int n_dims, const unsigned long shape[], - const std::vector& data) { - Typestring typestring_o(data); - std::string typestring = typestring_o.str(); - - std::ofstream stream(filename, std::ofstream::binary); - if (!stream) { - fprintf(stderr, "io error: failed to open a file."); - } - - std::vector shape_v(shape, shape + n_dims); - write_header(stream, typestring, fortran_order, shape_v); - - auto size = static_cast(comp_size(shape_v)); - - stream.write(reinterpret_cast(data.data()), - sizeof(Scalar) * size); -} - -template -inline void LoadArrayFromNumpy(const std::string& filename, - std::vector& shape, - std::vector& data) { - bool fortran_order; - LoadArrayFromNumpy(filename, shape, fortran_order, data); -} - -template -inline void LoadArrayFromNumpy(const std::string& filename, - std::vector& shape, - bool& fortran_order, std::vector& data) { - std::ifstream stream(filename, std::ifstream::binary); - if (!stream) { - fprintf(stderr, "io error: failed to open a file."); - } - - std::string header = read_header(stream); - - // parse header - std::string typestr; - - parse_header(header, typestr, fortran_order, shape); - - // check if the typestring matches the given one - Typestring typestring_o{data}; - std::string expect_typestr = typestring_o.str(); - if (typestr != expect_typestr) { - fprintf(stderr, "formatting error: typestrings not matching"); - } - - // compute the data size based on the shape - auto size = static_cast(comp_size(shape)); - data.resize(size); - - // read the data - stream.read(reinterpret_cast(data.data()), sizeof(Scalar) * size); -} - -inline void LoadArrayFromNumpy(const std::string& filename, - std::string& type_str, - std::vector& shape, - std::vector& data) { - std::ifstream stream(filename, std::ifstream::binary); - if (!stream) { - fprintf(stderr, "io error: failed to open a file."); - } - - std::string header = read_header(stream); - bool fortran_order; - // parse header - parse_header(header, type_str, fortran_order, shape); - - // check if the typestring matches the given one - std::string size_str = type_str.substr(type_str.size() - 1); - size_t elem_size = atoi(size_str.c_str()); - - // compute the data size based on the shape - auto byte_size = elem_size * static_cast(comp_size(shape)); - data.resize(byte_size); - - // read the data - stream.read(reinterpret_cast(data.data()), byte_size); -} - -} // namespace npy - -#endif // NPY_H diff --git a/sdk/load-and-run/src/text_table.cpp b/sdk/load-and-run/src/text_table.cpp deleted file mode 100644 index e3e8e9a6..00000000 --- a/sdk/load-and-run/src/text_table.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/** - * \file sdk/load-and-run/src/text_table.cpp - * MegEngine is Licensed under the Apache License, Version 2.0 (the "License") - * - * Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - */ - -#include "text_table.h" - -using namespace mgb; - -namespace { -inline void mid(std::ostream& os, const std::string& str, size_t max_w) { - size_t l = (max_w - str.length()) / 2 + str.length(); - size_t r = max_w - l; - os << std::setw(l) << std::right << str; - if (r > 0) os << std::setw(r) << ' '; -} -inline size_t char_length(char c) { return c ? 1 : 0; } -} // namespace - -void TextTable::adjuster_last_row() { - if (m_rows.empty()) return; - auto& row = m_rows.back(); - if (row.params.horizontal == 0 or row.params.vertical == 0) { - row.params.corner = 0; - } - if (row.params.horizontal != 0 && row.params.vertical != 0 && - row.params.corner == 0) { - row.params.corner = row.params.horizontal; - } -} - -void TextTable::show(std::ostream& os) { - if (m_rows.empty()) return; - auto& last_row = m_rows.front(); - bool first = true; - for (auto& row : m_rows) { - auto& lrow = - (last_row.values.size() * char_length(last_row.params.horizontal)) > - (row.values.size() * char_length(row.params.horizontal)) - ? last_row - : row; - // line before row - if (lrow.params.horizontal) { - if (not first) os << std::endl; - os << m_prefix; - if (lrow.params.corner) os << lrow.params.corner; - size_t skip_size = 0; - // table name - if (first) { - os << m_name; - skip_size = m_name.length(); - } - for (size_t i = 0; i < lrow.values.size(); ++i) { - auto max_w = m_cols_max_w.at(i) + m_padding * 2; - if (max_w + char_length(lrow.params.corner) <= skip_size) { - skip_size = - skip_size - max_w - char_length(lrow.params.corner); - continue; - } - size_t rest = - max_w + char_length(lrow.params.corner) - skip_size; - skip_size = 0; - if (rest > char_length(lrow.params.corner)) { - os << std::string(rest - char_length(lrow.params.corner), - lrow.params.horizontal); - rest = char_length(lrow.params.corner); - } - if (rest > 0 && lrow.params.corner) os << lrow.params.corner; - } - } else if (first) { - os << m_prefix << ' ' << m_name; - } - first = false; - os << std::endl << m_prefix; - if (row.params.vertical) os << row.params.vertical; - // row - for (size_t i = 0; i < row.values.size(); ++i) { - auto& str = row.values.at(i); - auto max_w = m_cols_max_w.at(i) + 2 * m_padding; - if (row.params.align == Align::Mid) { - mid(os, str, max_w); - } else if (row.params.align == Align::Left) { - os << std::setw(max_w) << std::left << str; - } else { - os << std::setw(max_w) << std::right << str; - } - if (row.params.vertical) os << row.params.vertical; - } - last_row = row; - } - if (last_row.params.horizontal) { - os << std::endl << m_prefix; - if (last_row.params.corner) os << last_row.params.corner; - for (size_t i = 0; i < last_row.values.size(); ++i) { - auto max_w = m_cols_max_w.at(i); - std::string tmp(max_w + m_padding * 2, last_row.params.horizontal); - os << tmp; - if (last_row.params.corner) os << last_row.params.corner; - } - } -} \ No newline at end of file diff --git a/sdk/load-and-run/src/text_table.h b/sdk/load-and-run/src/text_table.h deleted file mode 100644 index 9e88b042..00000000 --- a/sdk/load-and-run/src/text_table.h +++ /dev/null @@ -1,132 +0,0 @@ -/** - * \file sdk/load-and-run/src/text_table.h - * MegEngine is Licensed under the Apache License, Version 2.0 (the "License") - * - * Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include "megbrain/common.h" - -namespace mgb -{ - -class TextTable { -public: - enum Level { Summary, Detail }; - enum class Align : int { Left, Right, Mid }; - explicit TextTable(const std::string& table_name) : m_name(table_name) {} - TextTable& horizontal(char c) { - m_row.params.horizontal = c; - return *this; - } - TextTable& vertical(char c) { - m_row.params.vertical = c; - return *this; - } - TextTable& corner(char c) { - m_row.params.corner = c; - return *this; - } - TextTable& align(Align v) { - m_row.params.align = v; - return *this; - } - TextTable& padding(size_t w) { - m_padding = w; - return *this; - } - TextTable& prefix(const std::string& str) { - m_prefix = str; - return *this; - } - - template - TextTable& add(const T& value) { - m_row.values.emplace_back(value); - if (m_cols_max_w.size() < m_row.values.size()) { - m_cols_max_w.emplace_back(m_row.values.back().length()); - } else { - mgb_assert(m_row.values.size() >= 1); - size_t i = m_row.values.size() - 1; - m_cols_max_w[i] = - std::max(m_cols_max_w[i], m_row.values.back().length()); - } - return *this; - } - - template ::value, bool>::type = 0> - TextTable& add(const T& value) { - std::stringstream ss; - ss << std::setiosflags(std::ios::fixed) << std::setprecision(2); - ss << value; - m_row.values.emplace_back(ss.str()); - if (m_cols_max_w.size() < m_row.values.size()) { - m_cols_max_w.emplace_back(m_row.values.back().length()); - } else { - mgb_assert(m_row.values.size() >= 1); - size_t i = m_row.values.size() - 1; - m_cols_max_w[i] = - std::max(m_cols_max_w[i], m_row.values.back().length()); - } - return *this; - } - - template ::value, bool>::type = 0> - TextTable& add(const T& value) { - m_row.values.emplace_back(std::to_string(value)); - return *this; - } - - void eor() { - m_rows.emplace_back(m_row); - adjuster_last_row(); - m_row.values.clear(); - } - - void reset() { - m_row = {}; - m_cols_max_w.clear(); - m_padding = 0; - m_rows.clear(); - } - - void show(std::ostream& os); - -private: - void adjuster_last_row(); - std::string m_name; - std::vector m_cols_max_w; - size_t m_padding = 0; - std::string m_prefix = ""; - struct Row { - std::vector values; - struct Params { - Align align = Align::Left; - char horizontal = '-', vertical = '|', corner = '+'; - } params; - }; - std::vector m_rows; - Row m_row; -}; - -inline std::ostream& operator<<(std::ostream& stream, TextTable& table) { - table.show(stream); - return stream; -} - -} // namespace mgb \ No newline at end of file diff --git a/sdk/load-and-run/test/json_loader_test.cpp b/sdk/load-and-run/test/json_loader_test.cpp deleted file mode 100644 index 1bac85a9..00000000 --- a/sdk/load-and-run/test/json_loader_test.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/** - * \file sdk/load-and-run/test/test_json_loader.cpp - * MegEngine is Licensed under the Apache License, Version 2.0 (the "License") - * - * Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - */ - -#include -#include -#include -#include -#include "../src/json_loader.h" - -using namespace mgb; - -void test_number(double real, std::string str) { - JsonLoader json; - auto root = json.load(str.data(), str.size()); - mgb_assert(root->is_number()); - mgb_assert(std::fabs(real - root->number()) <= DBL_EPSILON); -} - -void test_string(std::string str, std::string json_str) { - JsonLoader json; - auto root = json.load(json_str.data(), json_str.size()); - mgb_assert(root->is_str()); - mgb_assert(str == root->str()); -} - -void test_array(size_t num, std::string str) { - JsonLoader json; - auto root = json.load(str.data(), str.size()); - mgb_assert(root->is_array()); - mgb_assert(root->len() == num); -} - -void test_object(size_t num, std::string str) { - JsonLoader json; - auto root = json.load(str.data(), str.size()); - mgb_assert(root->is_object()); - mgb_assert(root->len() == num); -} - -int main() { - test_number(1.0, "1.0"); - test_number(1e10, "1e10"); - test_number(0.2345678, "0.02345678e1"); - test_number(-10086, "-1.0086E4"); - test_number(1.7976931348623157e+308, - "1.7976931348623157e+308"); // max double - - test_string("a", "\"a\""); - test_string("\\table", "\"\\table\""); - - test_array(0, " [ ] "); - test_array(4, " [ 0.1, 0.2,0.3, 1990 ] "); - test_array(2, " [ 0.1, \"hello-world\"]"); - test_array(3, " [ 0.1, \"hello-world\", [2.0, 33]]"); - test_array(1, " [ [ [ [2020] ], [2021], [[2022]] ] ]"); - - test_object(0, " { } "); - test_object(1, "{\"key1\": 2023}"); - test_object(1, - "{\"key1\": { \"key2\": { " - "\"key3\": \"value\" } } }"); - test_object(1, "{\"key1\":{\"key2\":{}}}"); - - printf("test passed\n"); - return 0; -} \ No newline at end of file