-set(SOFT_BACKEND_COMMON_SOURCES src/soft_backend.cpp src/generator.cpp src/model_analyzer.cpp)
-set(SOFT_BACKEND_CPP_SOURCES src/cpp_backend.cpp)
-set(SOFT_BACKEND_C_SOURCES src/c_backend.cpp)
+set(SOFT_BACKEND_COMMON_SOURCES src/soft_backend.cpp src/base_generator.cpp src/model_analyzer.cpp)
+set(SOFT_BACKEND_CPP_SOURCES src/cpp_backend.cpp src/cpp_generator.cpp)
+set(SOFT_BACKEND_C_SOURCES src/c_backend.cpp src/c_generator.cpp)
set(DEF_CONV src/def2src.cpp)
file(GLOB_RECURSE TESTS "src/*.test.cpp")
make_soft_backend(soft_backend_cpp ${SOFT_BACKEND_CPP_SOURCES})
make_soft_backend(soft_backend_c ${SOFT_BACKEND_C_SOURCES})
-add_nncc_test(nnc_soft_backend_test ${TESTS} ${SOFT_BACKEND_COMMON_SOURCES})
+add_nncc_test(nnc_soft_backend_test ${TESTS} ${SOFT_BACKEND_COMMON_SOURCES} ${SOFT_BACKEND_CPP_SOURCES})
nncc_target_link_libraries(nnc_soft_backend_test nncc_core nnc_core nnc_plugin_core nncc_foundation soft_backend_common)
target_include_directories(nnc_soft_backend_test PUBLIC include)
target_include_directories(nnc_soft_backend_test PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
--- /dev/null
+#ifndef _NNC_SOFT_BACKEND_BASE_GENERATOR_H_
+#define _NNC_SOFT_BACKEND_BASE_GENERATOR_H_
+
+#include "nnc/core/IR/model/graph/graph.h"
+
+#include <string>
+#include <ostream>
+
+namespace nncc
+{
+namespace contrib
+{
+namespace backend
+{
+namespace soft
+{
+
+class ModelAnalyzer;
+
+class BaseCodeGenerator
+{
+public:
+ void generate(nncc::contrib::core::IR::model::Graph *g);
+
+protected:
+ virtual void formatTensorNames(const ModelAnalyzer &ma) = 0;
+ virtual void materializeHeader(std::ostream &out, const ModelAnalyzer &ma) = 0;
+ virtual void materializeCode(std::ostream &out, const ModelAnalyzer &ma) = 0;
+ void materializeModelParams(std::ostream &out, const ModelAnalyzer &ma);
+
+ BaseCodeGenerator(BaseCodeGenerator &g) = default;
+
+ // check validity of selected output files, throws appropriate exception on error
+ void checkCorrectness();
+
+ BaseCodeGenerator(const std::string &headerFile,
+ const std::string &codeFile, const std::string &modelFile);
+
+ std::vector<std::string> _formattedTensors;
+
+ // Code output file
+ std::string _headerFile;
+ // Code output file
+ std::string _codeFile;
+ // Model output file
+ std::string _modelFile;
+};
+
+} // namespace soft
+} // namespace backend
+} // namespace contrib
+} // namespace nncc
+
+#endif //_NNC_SOFT_BACKEND_BASE_GENERATOR_H_
--- /dev/null
+#ifndef _NNC_SOFT_BACKEND_C_GENERATOR_H_
+#define _NNC_SOFT_BACKEND_C_GENERATOR_H_
+
+#include "base_generator.h"
+
+namespace nncc
+{
+namespace contrib
+{
+namespace backend
+{
+namespace soft
+{
+
+// C generator
+class CCodeGenerator: public BaseCodeGenerator
+{
+ CCodeGenerator(const std::string &headerFile, const std::string &codeFile, const std::string &modelFile):
+ BaseCodeGenerator(headerFile, codeFile, modelFile)
+ {
+ // EMPTY
+ }
+
+public:
+ static CCodeGenerator create(const std::string &headerFile,
+ const std::string &codeFile,
+ const std::string &modelFile);
+
+protected:
+ void formatTensorNames(const ModelAnalyzer &ma) override;
+ void materializeHeader(std::ostream &out, const ModelAnalyzer &ma) override;
+ void materializeCode(std::ostream &out, const ModelAnalyzer &ma) override;
+};
+
+} // namespace soft
+} // namespace backend
+} // namespace contrib
+} // namespace nncc
+
+#endif //_NNC_SOFT_BACKEND_C_GENERATOR_H_
--- /dev/null
+#ifndef _NNC_SOFT_BACKEND_CPP_GENERATOR_H_
+#define _NNC_SOFT_BACKEND_CPP_GENERATOR_H_
+
+#include "base_generator.h"
+
+namespace nncc
+{
+namespace contrib
+{
+namespace backend
+{
+namespace soft
+{
+
+// C++ generator
+class CPPCodeGenerator: public BaseCodeGenerator
+{
+ CPPCodeGenerator(const std::string &headerFile, const std::string &codeFile, const std::string &modelFile):
+ BaseCodeGenerator(headerFile, codeFile, modelFile)
+ {
+ // EMPTY
+ }
+
+public:
+ static CPPCodeGenerator create(const std::string &headerFile,
+ const std::string &codeFile,
+ const std::string &modelFile);
+
+protected:
+ void formatTensorNames(const ModelAnalyzer &ma) override;
+ void materializeHeader(std::ostream &out, const ModelAnalyzer &ma) override;
+
+ void gatherOperationArguments(const ModelAnalyzer &ma,
+ const std::vector<size_t> &argIds,
+ std::vector<std::string> &args);
+ void materializeInferenceSequence(std::ostream &out, const ModelAnalyzer &ma);
+ void materializeCode(std::ostream &out, const ModelAnalyzer &ma) override;
+};
+
+} // namespace soft
+} // namespace backend
+} // namespace contrib
+} // namespace nncc
+
+#endif //_NNC_SOFT_BACKEND_CPP_GENERATOR_H_
+++ /dev/null
-#ifndef _NNC_SOFT_BACKEND_GENERATOR_H_
-#define _NNC_SOFT_BACKEND_GENERATOR_H_
-
-#include "nnc/core/IR/model/graph/graph.h"
-
-#include <string>
-#include <ostream>
-
-namespace nncc
-{
-namespace contrib
-{
-namespace backend
-{
-namespace soft
-{
-
-class ModelAnalyzer;
-
-class BaseCodeGenerator
-{
-public:
- void generate(nncc::contrib::core::IR::model::Graph *g);
-
-protected:
- virtual void formatTensorNames(const ModelAnalyzer &ma) = 0;
- virtual void materializeHeader(std::ostream &out, const ModelAnalyzer &ma) = 0;
- virtual void materializeCode(std::ostream &out, const ModelAnalyzer &ma) = 0;
- void materializeModelParams(std::ostream &out, const ModelAnalyzer &ma);
-
- BaseCodeGenerator(BaseCodeGenerator &g) = default;
-
- // check validity of selected output files, throws appropriate exception on error
- void checkCorrectness();
-
- BaseCodeGenerator(const std::string &headerFile,
- const std::string &codeFile, const std::string &modelFile);
-
- std::vector<std::string> _formattedTensors;
-
- // Code output file
- std::string _headerFile;
- // Code output file
- std::string _codeFile;
- // Model output file
- std::string _modelFile;
-};
-
-// C++ generator
-class CPPCodeGenerator: public BaseCodeGenerator
-{
- CPPCodeGenerator(const std::string &headerFile, const std::string &codeFile, const std::string &modelFile):
- BaseCodeGenerator(headerFile, codeFile, modelFile)
- {
- // EMPTY
- }
-
-public:
- static CPPCodeGenerator create(const std::string &headerFile,
- const std::string &codeFile,
- const std::string &modelFile);
-
-protected:
- void formatTensorNames(const ModelAnalyzer &ma) override;
- void materializeHeader(std::ostream &out, const ModelAnalyzer &ma) override;
-
- void gatherOperationArguments(const ModelAnalyzer &ma,
- const std::vector<size_t> &argIds,
- std::vector<std::string> &args);
- void materializeInferenceSequence(std::ostream &out, const ModelAnalyzer &ma);
- void materializeCode(std::ostream &out, const ModelAnalyzer &ma) override;
-};
-
-// C generator
-class CCodeGenerator: public BaseCodeGenerator
-{
- CCodeGenerator(const std::string &headerFile, const std::string &codeFile, const std::string &modelFile):
- BaseCodeGenerator(headerFile, codeFile, modelFile)
- {
- // EMPTY
- }
-
-public:
- static CCodeGenerator create(const std::string &headerFile,
- const std::string &codeFile,
- const std::string &modelFile);
-
-protected:
- void formatTensorNames(const ModelAnalyzer &ma) override;
- void materializeHeader(std::ostream &out, const ModelAnalyzer &ma) override;
- void materializeCode(std::ostream &out, const ModelAnalyzer &ma) override;
-};
-
-} // namespace soft
-} // namespace backend
-} // namespace contrib
-} // namespace nncc
-
-#endif //_NNC_SOFT_BACKEND_GENERATOR_H_
--- /dev/null
+#include "base_generator.h"
+#include "model_analyzer.h"
+#include "PluginException.h"
+#include "nnc/core/IR/model/actions/ShapeInference.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <cerrno>
+#include <cstring>
+#include <fstream>
+#include <memory>
+#include <fcntl.h>
+
+using namespace std;
+using namespace nncc::contrib;
+using namespace nncc::contrib::core::IR::model;
+
+namespace nncc
+{
+namespace contrib
+{
+namespace backend
+{
+namespace soft
+{
+
+namespace parameters_format
+{
+const int MAGIC_LEN = 4;
+const int VERSION_LEN = 4;
+const int HASH_LEN = 4;
+const int HEADER_LEN = MAGIC_LEN + VERSION_LEN + HASH_LEN;
+
+const char MAGIC[MAGIC_LEN + 1] = "NNMP"; // Neural Network Model Parameters
+}
+
+namespace
+{
+
+bool areFilesEqual(const struct stat &f1, const struct stat &f2)
+{
+ return f1.st_dev == f2.st_dev && f1.st_ino == f2.st_ino;
+}
+
+bool fillFileStats(const string &path, struct stat &s)
+{
+ if (path.empty())
+ return false;
+ if (stat(path.c_str(), &s))
+ {
+ if (errno == ENOENT)
+ {
+ // file not found, try to create it
+ ofstream f(path);
+ if (!f.good())
+ throw PluginException("Can not create output file: " + path);
+ // try again
+ int res = stat(path.c_str(), &s);
+ (void) res;
+ // on this step everythink should be fine, since we just created file
+ assert(!res);
+ return true;
+ }
+ else
+ throw PluginException("Can not get info for file: " + path);
+ }
+ // check that selected file is regular or char device(to accept /dev/null, and simular)
+ if (!(s.st_mode & (S_IFREG | S_IFCHR)))
+ throw PluginException("Not a regular file: " + path);
+ return true;
+}
+
+using ostream_ptr = unique_ptr<ostream, void (*)(ostream *)>;
+
+ostream_ptr getStream(const string &path)
+{
+ if (path.empty())
+ return ostream_ptr(&cout, [](ostream *){});
+ ofstream *ofs = new ofstream(path);
+ if (ofs->fail())
+ {
+ delete ofs;
+ throw PluginException("Can not open code output file: " + path);
+ }
+ return ostream_ptr(ofs, [](ostream *ofs){delete ofs;});
+}
+
+} // unnamed namespace
+
+BaseCodeGenerator::BaseCodeGenerator(const string &headerFile, const string &codeFile, const string &modelFile):
+ _headerFile(headerFile), _codeFile(codeFile), _modelFile(modelFile)
+{
+ // EMPTY
+}
+
+void BaseCodeGenerator::checkCorrectness()
+{
+ // check that header, code and model file paths refers to different files.
+ // Exception: stdout could be common output stream
+ struct stat headerStat, codeStat, modelStat;
+ bool checkHeader = fillFileStats(_headerFile, headerStat);
+ bool checkCode = fillFileStats(_codeFile, codeStat);
+ bool checkModel = fillFileStats(_modelFile, modelStat);
+
+ if ((checkHeader && checkCode && areFilesEqual(headerStat, codeStat)) ||
+ (checkHeader && checkModel && areFilesEqual(headerStat, modelStat)) ||
+ (checkCode && checkModel && areFilesEqual(codeStat, modelStat)))
+ {
+ throw PluginException("output files should not be equal");
+ }
+}
+
+void BaseCodeGenerator::materializeModelParams(ostream &out, const ModelAnalyzer &ma)
+{
+ using namespace parameters_format;
+
+ // First form a dump header
+ char header[HEADER_LEN];
+ uint32_t version = ma.getFormatVersion();
+ uint32_t hash = ma.getModelHash();
+ static_assert(VERSION_LEN == sizeof(version), "version length mismatch");
+ static_assert(HASH_LEN == sizeof(hash), "hash length mismatch");
+ memcpy(header, MAGIC, MAGIC_LEN);
+ memcpy(header + MAGIC_LEN, &version, VERSION_LEN);
+ memcpy(header + MAGIC_LEN + VERSION_LEN, &hash, HASH_LEN);
+
+ out.write(header, HEADER_LEN);
+ if (out.fail())
+ {
+ throw PluginException("Failed to write model parameters header");
+ }
+ auto ¶ms = ma.getPackedParameters();
+ out.write(params.data(), params.size());
+ if (out.fail())
+ {
+ throw PluginException("Failed to write model Parameters");
+ }
+}
+
+void BaseCodeGenerator::generate(Graph *g)
+{
+ // inference shapes
+ core::IR::model::ShapeInference si;
+ g->accept(&si);
+ // visit and analyze graph
+ ModelAnalyzer ma;
+ g->accept(&ma);
+ // rename tensors for specific backend language
+ formatTensorNames(ma);
+ // Print header
+ auto headerStream = getStream(_headerFile);
+ materializeHeader(*headerStream, ma);
+ headerStream.reset();
+
+ // Print code
+ auto codeStream = getStream(_codeFile);
+ materializeCode(*codeStream, ma);
+ codeStream.reset();
+
+ // Print model parameters
+ auto modelStream = getStream(_modelFile);
+ materializeModelParams(*modelStream, ma);
+ modelStream.reset();
+}
+
+} // namespace soft
+} // namespace backend
+} // namespace contrib
+} // namespace nncc
+
#include "soft_backend.h"
-#include "generator.h"
+#include "c_generator.h"
#include "ConfigException.h"
--- /dev/null
+#include "c_generator.h"
+#include "model_analyzer.h"
+
+using namespace std;
+using namespace nncc::contrib;
+using namespace nncc::contrib::core::IR::model;
+
+namespace nncc
+{
+namespace contrib
+{
+namespace backend
+{
+namespace soft
+{
+
+CCodeGenerator CCodeGenerator::create(const string &headerFile,
+ const string &codeFile,
+ const string &modelFile)
+{
+ CCodeGenerator gen(headerFile, codeFile, modelFile);
+ gen.checkCorrectness();
+ return gen;
+}
+
+void CCodeGenerator::formatTensorNames(const ModelAnalyzer &ma)
+{
+ // TODO format tensor names according to c backend requirements
+}
+
+void CCodeGenerator::materializeHeader(ostream &out, const ModelAnalyzer &ma)
+{
+ // TODO emit C header to out stream
+}
+
+void CCodeGenerator::materializeCode(ostream &out, const ModelAnalyzer &ma)
+{
+ // TODO emit C code to out stream
+}
+
+} // namespace soft
+} // namespace backend
+} // namespace contrib
+} // namespace nncc
+
#include "soft_backend.h"
-#include "generator.h"
+#include "cpp_generator.h"
#include "ConfigException.h"
-#include "generator.h"
+#include "cpp_generator.h"
#include "model_analyzer.h"
#include "PluginException.h"
-#include "nnc/core/IR/model/actions/ShapeInference.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <cerrno>
-#include <cstring>
-#include <fstream>
-#include <memory>
-#include <fcntl.h>
-#include <map>
#include "param_constants.def"
namespace soft
{
-namespace
-{
-
-bool areFilesEqual(const struct stat &f1, const struct stat &f2)
-{
- return f1.st_dev == f2.st_dev && f1.st_ino == f2.st_ino;
-}
-
-bool fillFileStats(const string &path, struct stat &s)
-{
- if (path.empty())
- return false;
- if (stat(path.c_str(), &s))
- {
- if (errno == ENOENT)
- {
- // file not found, try to create it
- ofstream f(path);
- if (!f.good())
- throw PluginException("Can not create output file: " + path);
- // try again
- int res = stat(path.c_str(), &s);
- (void) res;
- // on this step everythink should be fine, since we just created file
- assert(!res);
- return true;
- }
- else
- throw PluginException("Can not get info for file: " + path);
- }
- // check that selected file is regular or char device(to accept /dev/null, and simular)
- if (!(s.st_mode & (S_IFREG | S_IFCHR)))
- throw PluginException("Not a regular file: " + path);
- return true;
-}
-
-using ostream_ptr = unique_ptr<ostream, void (*)(ostream *)>;
-
-ostream_ptr getStream(const string &path)
-{
- if (path.empty())
- return ostream_ptr(&cout, [](ostream *){});
- ofstream *ofs = new ofstream(path);
- if (ofs->fail())
- {
- delete ofs;
- throw PluginException("Can not open code output file: " + path);
- }
- return ostream_ptr(ofs, [](ostream *ofs){delete ofs;});
-}
-
-} // unnamed namespace
-
-BaseCodeGenerator::BaseCodeGenerator(const string &headerFile, const string &codeFile, const string &modelFile):
- _headerFile(headerFile), _codeFile(codeFile), _modelFile(modelFile)
-{
- // EMPTY
-}
-
-void BaseCodeGenerator::checkCorrectness()
-{
- // check that header, code and model file paths refers to different files.
- // Exception: stdout could be common output stream
- struct stat headerStat, codeStat, modelStat;
- bool checkHeader = fillFileStats(_headerFile, headerStat);
- bool checkCode = fillFileStats(_codeFile, codeStat);
- bool checkModel = fillFileStats(_modelFile, modelStat);
-
- if ((checkHeader && checkCode && areFilesEqual(headerStat, codeStat)) ||
- (checkHeader && checkModel && areFilesEqual(headerStat, modelStat)) ||
- (checkCode && checkModel && areFilesEqual(codeStat, modelStat)))
- {
- throw PluginException("output files should not be equal");
- }
-}
-
-void BaseCodeGenerator::materializeModelParams(ostream &out, const ModelAnalyzer &ma)
-{
- using namespace params;
-
- // First form a dump header
- char header[HEADER_LEN];
- uint32_t version = ma.getFormatVersion();
- uint32_t hash = ma.getModelHash();
- static_assert(VERSION_LEN == sizeof(version), "version length mismatch");
- static_assert(HASH_LEN == sizeof(hash), "hash length mismatch");
- memcpy(header, MAGIC, MAGIC_LEN);
- memcpy(header + MAGIC_LEN, &version, VERSION_LEN);
- memcpy(header + MAGIC_LEN + VERSION_LEN, &hash, HASH_LEN);
-
- out.write(header, HEADER_LEN);
- if (out.fail())
- {
- throw PluginException("Failed to write model parameters header");
- }
- auto ¶msVec = ma.getPackedParameters();
- out.write(paramsVec.data(), paramsVec.size());
- if (out.fail())
- {
- throw PluginException("Failed to write model Parameters");
- }
-}
-
-void BaseCodeGenerator::generate(Graph *g)
-{
- // inference shapes
- core::IR::model::ShapeInference si;
- g->accept(&si);
- // visit and analyze graph
- ModelAnalyzer ma;
- g->accept(&ma);
- // rename tensors for specific backend language
- formatTensorNames(ma);
- // Print header
- auto headerStream = getStream(_headerFile);
- materializeHeader(*headerStream, ma);
- headerStream.reset();
-
- // Print code
- auto codeStream = getStream(_codeFile);
- materializeCode(*codeStream, ma);
- codeStream.reset();
-
- // Print model parameters
- auto modelStream = getStream(_modelFile);
- materializeModelParams(*modelStream, ma);
- modelStream.reset();
-}
-
-CCodeGenerator CCodeGenerator::create(const std::string &headerFile,
- const std::string &codeFile,
- const std::string &modelFile)
-{
- CCodeGenerator gen(headerFile, codeFile, modelFile);
- gen.checkCorrectness();
- return gen;
-}
-
-void CCodeGenerator::formatTensorNames(const ModelAnalyzer &ma)
-{
- // TODO format tensor names according to c backend requirements
-}
-
-void CCodeGenerator::materializeHeader(ostream &out, const ModelAnalyzer &ma)
-{
- // TODO emit C header to out stream
-}
-
-void CCodeGenerator::materializeCode(ostream &out, const ModelAnalyzer &ma)
-{
- // TODO emit C code to out stream
-}
-
CPPCodeGenerator CPPCodeGenerator::create(const std::string &headerFile,
const std::string &codeFile,
const std::string &modelFile)
}
}
}
- _formattedTensors.push_back(std::move(formattedName));
+ _formattedTensors.push_back(move(formattedName));
}
}
-#include "generator.h"
+#include "cpp_generator.h"
+
#include "PluginException.h"
#include <gtest/gtest.h>
#include "ConfigException.h"
#include "PluginType.h"
#include "nnc/core/IR/model/graph/graph.h"
-#include "generator.h"
+#include "cpp_generator.h"
+#include "c_generator.h"
using namespace std;
using namespace nncc::contrib;