diff --git a/paddle/trainer/TrainerConfigHelper.cpp b/paddle/trainer/TrainerConfigHelper.cpp index 60ac8459a12db8..dc1436dfe5985b 100644 --- a/paddle/trainer/TrainerConfigHelper.cpp +++ b/paddle/trainer/TrainerConfigHelper.cpp @@ -38,7 +38,8 @@ struct TrainerConfigHelperPrivate { TrainerConfig conf; }; -TrainerConfigHelper::TrainerConfigHelper(const std::string &configFilePath) +TrainerConfigHelper::TrainerConfigHelper( + const std::string &configFilePath) throw(ErrorPtr &) : m(new TrainerConfigHelperPrivate()) { std::ostringstream configArgs; configArgs << "trainer_id=" << FLAGS_trainer_id << ",local=" << FLAGS_local @@ -50,11 +51,19 @@ TrainerConfigHelper::TrainerConfigHelper(const std::string &configFilePath) } VLOG(3) << "Parsing trainer config " << configFilePath; + std::string errStr; std::string configProtoStr = callPythonFunc(kConfigParserModuleName, kConfigParserFuncName, - {configFilePath, configArgs.str()}); - CHECK(m->conf.ParseFromString(configProtoStr)); + {configFilePath, configArgs.str()}, + &errStr); + if (!errStr.empty()) { + Error::throwError(errStr); + } + + if (!m->conf.ParseFromString(configProtoStr)) { + Error::throwError("cannot parse configuration proto string"); + } } TrainerConfigHelper::TrainerConfigHelper(const TrainerConfig &config) diff --git a/paddle/trainer/TrainerConfigHelper.h b/paddle/trainer/TrainerConfigHelper.h index f1366cc041b0d9..50daa3dc387164 100644 --- a/paddle/trainer/TrainerConfigHelper.h +++ b/paddle/trainer/TrainerConfigHelper.h @@ -14,6 +14,7 @@ limitations under the License. */ #pragma once +#include #include #include #include @@ -32,11 +33,8 @@ class DataConfig; * * The all operation to TrainerConfig object should use this object. It remove * many copy & paste code in trainer. - * - * @TODO(yuyang18): Make cmake check compiler support keyword 'final' or not. - * Define a macro to unify 'final' keyword */ -class TrainerConfigHelper /*final*/ { +class TrainerConfigHelper final { public: DISABLE_COPY(TrainerConfigHelper); @@ -44,7 +42,8 @@ class TrainerConfigHelper /*final*/ { * @brief Ctor, Create a TrainerConfig from config file * @param configFilePath Config file path. */ - explicit TrainerConfigHelper(const std::string& configFilePath); + explicit TrainerConfigHelper(const std::string& configFilePath) throw( + ErrorPtr&); explicit TrainerConfigHelper(const TrainerConfig& config); /** diff --git a/paddle/utils/Error.cpp b/paddle/utils/Error.cpp new file mode 100644 index 00000000000000..a0aa5951be7e6a --- /dev/null +++ b/paddle/utils/Error.cpp @@ -0,0 +1,18 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#include "Error.h" + +namespace paddle { +void paddle::Error::throwError(const std::string &what) throw(ErrorPtr &) { + throw std::unique_ptr(new Error(what)); +} +} // namespace paddle diff --git a/paddle/utils/Error.h b/paddle/utils/Error.h new file mode 100644 index 00000000000000..aeee1f888367a1 --- /dev/null +++ b/paddle/utils/Error.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#pragma once +#include +#include +namespace paddle { +typedef std::unique_ptr ErrorPtr; +class Error : public std::exception { +public: + explicit inline Error(const std::string& what) noexcept : what_(what) {} + virtual const char* what() const noexcept { return this->what_.c_str(); } + + static void throwError(const std::string& what) throw(ErrorPtr&); + +private: + std::string what_; +}; + +} // namespace paddle diff --git a/paddle/utils/PythonUtil.cpp b/paddle/utils/PythonUtil.cpp index 7faeff55c28b90..f497f0cfafee8c 100644 --- a/paddle/utils/PythonUtil.cpp +++ b/paddle/utils/PythonUtil.cpp @@ -116,26 +116,39 @@ static void printPyErrorStack(std::ostream& os, } PyObjectPtr callPythonFuncRetPyObj(const std::string& moduleName, const std::string& funcName, - const std::vector& args) { + const std::vector& args, + std::string* errorString) { PyGuard guard; - PyObjectPtr pyModule = py::import(moduleName); + PyObjectPtr pyModule = py::import(moduleName, errorString); + if (pyModule == nullptr) { + return nullptr; + } + PyObjectPtr pyFunc(PyObject_GetAttrString(pyModule.get(), funcName.c_str())); - CHECK_PY(pyFunc) << "GetAttrString failed."; + CHECK_PY_WITH_ERRORSTR( + pyFunc, "GetAttrString failed.", errorString, return nullptr); PyObjectPtr pyArgs(PyTuple_New(args.size())); for (size_t i = 0; i < args.size(); ++i) { PyObjectPtr pyArg(PyString_FromString(args[i].c_str())); - CHECK_PY(pyArg) << "Import pyArg failed."; + CHECK_PY_WITH_ERRORSTR( + pyArg, "Import pyArg failed.", errorString, return nullptr); PyTuple_SetItem(pyArgs.get(), i, pyArg.release()); // Maybe a problem } PyObjectPtr ret(PyObject_CallObject(pyFunc.get(), pyArgs.get())); - CHECK_PY(ret) << "Call Object failed."; + CHECK_PY_WITH_ERRORSTR( + ret, "Call Object failed", errorString, return nullptr); return ret; } std::string callPythonFunc(const std::string& moduleName, const std::string& funcName, - const std::vector& args) { - PyObjectPtr obj = callPythonFuncRetPyObj(moduleName, funcName, args); + const std::vector& args, + std::string* errorString) { + PyObjectPtr obj = + callPythonFuncRetPyObj(moduleName, funcName, args, errorString); + if (obj == nullptr) { + return std::string(""); + } return std::string(PyString_AsString(obj.get()), PyString_Size(obj.get())); } @@ -181,10 +194,18 @@ std::string getPyCallStack() { return os.str(); } -PyObjectPtr import(const std::string& moduleName) { +PyObjectPtr import(const std::string& moduleName, std::string* errorString) { auto module = PyImport_ImportModule(moduleName.c_str()); - CHECK_PY(module) << "Import " << moduleName << "Error"; - return PyObjectPtr(module); + if (errorString == nullptr) { + CHECK_PY(module) << "Import " << moduleName << "Error"; + return PyObjectPtr(module); + } else { + if (module == nullptr) { + *errorString = getPyCallStack(); + return nullptr; + } + return PyObjectPtr(module); + } } } // namespace py diff --git a/paddle/utils/PythonUtil.h b/paddle/utils/PythonUtil.h index daebaffc855518..dab6b2017518f7 100644 --- a/paddle/utils/PythonUtil.h +++ b/paddle/utils/PythonUtil.h @@ -46,7 +46,8 @@ namespace paddle { std::string callPythonFunc(const std::string& moduleName, const std::string& funcName, - const std::vector& args); + const std::vector& args, + std::string* errorString = nullptr); #ifndef PADDLE_NO_PYTHON @@ -76,7 +77,8 @@ typedef std::unique_ptr PyObjectPtr; PyObjectPtr callPythonFuncRetPyObj(const std::string& moduleName, const std::string& funcName, - const std::vector& args); + const std::vector& args, + std::string* errorString = nullptr); PyObjectPtr createPythonClass(const std::string& moduleName, const std::string& className, @@ -84,9 +86,20 @@ PyObjectPtr createPythonClass(const std::string& moduleName, const std::map& kwargs); #define CHECK_PY(x) CHECK((x) != nullptr) << ::paddle::py::getPyCallStack() +#define CHECK_PY_WITH_ERRORSTR(x, extraMsg, errStr, ...) \ + do { \ + if ((errStr) == nullptr) { \ + CHECK_PY(x) << (extraMsg); \ + } else if ((x) == nullptr) { \ + *(errStr) = (extraMsg); \ + *(errStr) += ::paddle::py::getPyCallStack(); \ + __VA_ARGS__; \ + } \ + } while (0) namespace py { -PyObjectPtr import(const std::string& moduleName); +PyObjectPtr import(const std::string& moduleName, + std::string* errorString = nullptr); /** * Cast a PyLong or PyInt to int type T. diff --git a/paddle/utils/Util.cpp b/paddle/utils/Util.cpp index 411a64aa8d0737..d54b29fab5247a 100644 --- a/paddle/utils/Util.cpp +++ b/paddle/utils/Util.cpp @@ -27,6 +27,7 @@ limitations under the License. */ #include #include "CustomStackTrace.h" +#include "Error.h" #include "Logging.h" #include "StringUtil.h" #include "Thread.h" @@ -143,7 +144,19 @@ void runInitFunctions() { }); } +static void logAllUnhandledExceptions() { + try { + throw; + } catch (ErrorPtr& err) { + std::cerr << err->what() << "\n"; + } catch (...) { + std::cerr << "Unsupported error occured"; + } + exit(1); +} + void initMain(int argc, char** argv) { + std::set_terminate(logAllUnhandledExceptions); initializeLogging(argc, argv); installLayerStackTracer(); std::string line;