#ifndef CAFFE2_CORE_INIT_H_
|
#define CAFFE2_CORE_INIT_H_
|
|
#include "caffe2/core/common.h"
|
#include "caffe2/core/flags.h"
|
#include "caffe2/core/logging.h"
|
|
namespace caffe2 {
|
|
namespace internal {
|
class CAFFE2_API Caffe2InitializeRegistry {
|
public:
|
typedef bool (*InitFunction)(int*, char***);
|
// Registry() is defined in .cpp file to make registration work across
|
// multiple shared libraries loaded with RTLD_LOCAL
|
static Caffe2InitializeRegistry* Registry();
|
|
void Register(
|
InitFunction function,
|
bool run_early,
|
const char* description,
|
const char* name = nullptr) {
|
if (name) {
|
named_functions_[name] = function;
|
}
|
if (run_early) {
|
// Disallow registration after GlobalInit of early init functions
|
CAFFE_ENFORCE(!early_init_functions_run_yet_);
|
early_init_functions_.emplace_back(function, description);
|
} else {
|
if (init_functions_run_yet_) {
|
// Run immediately, since GlobalInit already ran. This should be
|
// rare but we want to allow it in some cases.
|
LOG(WARNING) << "Running init function after GlobalInit: "
|
<< description;
|
// TODO(orionr): Consider removing argc and argv for non-early
|
// registration. Unfortunately that would require a new InitFunction
|
// typedef, so not making the change right now.
|
//
|
// Note that init doesn't receive argc and argv, so the function
|
// might fail and we want to raise an error in that case.
|
int argc = 0;
|
char** argv = nullptr;
|
bool success = (function)(&argc, &argv);
|
CAFFE_ENFORCE(success);
|
} else {
|
// Wait until GlobalInit to run
|
init_functions_.emplace_back(function, description);
|
}
|
}
|
}
|
|
bool RunRegisteredEarlyInitFunctions(int* pargc, char*** pargv) {
|
CAFFE_ENFORCE(!early_init_functions_run_yet_);
|
early_init_functions_run_yet_ = true;
|
return RunRegisteredInitFunctionsInternal(
|
early_init_functions_, pargc, pargv);
|
}
|
|
bool RunRegisteredInitFunctions(int* pargc, char*** pargv) {
|
CAFFE_ENFORCE(!init_functions_run_yet_);
|
init_functions_run_yet_ = true;
|
return RunRegisteredInitFunctionsInternal(init_functions_, pargc, pargv);
|
}
|
|
bool RunNamedFunction(const char* name, int* pargc, char*** pargv) {
|
if (named_functions_.count(name)) {
|
return named_functions_[name](pargc, pargv);
|
}
|
return false;
|
}
|
|
private:
|
// Run all registered initialization functions. This has to be called AFTER
|
// all static initialization are finished and main() has started, since we are
|
// using logging.
|
bool RunRegisteredInitFunctionsInternal(
|
vector<std::pair<InitFunction, const char*>>& functions,
|
int* pargc, char*** pargv) {
|
for (const auto& init_pair : functions) {
|
VLOG(1) << "Running init function: " << init_pair.second;
|
if (!(*init_pair.first)(pargc, pargv)) {
|
LOG(ERROR) << "Initialization function failed.";
|
return false;
|
}
|
}
|
return true;
|
}
|
|
Caffe2InitializeRegistry() {}
|
vector<std::pair<InitFunction, const char*> > early_init_functions_;
|
vector<std::pair<InitFunction, const char*> > init_functions_;
|
std::unordered_map<std::string, InitFunction> named_functions_;
|
bool early_init_functions_run_yet_ = false;
|
bool init_functions_run_yet_ = false;
|
};
|
} // namespace internal
|
|
CAFFE2_API bool unsafeRunCaffe2InitFunction(
|
const char* name,
|
int* pargc = nullptr,
|
char*** pargv = nullptr);
|
|
class CAFFE2_API InitRegisterer {
|
public:
|
InitRegisterer(
|
internal::Caffe2InitializeRegistry::InitFunction function,
|
bool run_early,
|
const char* description,
|
const char* name = nullptr) {
|
internal::Caffe2InitializeRegistry::Registry()->Register(
|
function, run_early, description, name);
|
}
|
};
|
|
#define REGISTER_CAFFE2_INIT_FUNCTION(name, function, description) \
|
namespace { \
|
::caffe2::InitRegisterer \
|
g_caffe2_initregisterer_##name(function, false, description, #name); \
|
} // namespace
|
|
#define REGISTER_CAFFE2_EARLY_INIT_FUNCTION(name, function, description) \
|
namespace { \
|
::caffe2::InitRegisterer \
|
g_caffe2_initregisterer_##name(function, true, description, #name); \
|
} // namespace
|
|
/**
|
* @brief Determine whether GlobalInit has already been run
|
*/
|
CAFFE2_API bool GlobalInitAlreadyRun();
|
|
class CAFFE2_API GlobalInitIsCalledGuard {
|
public:
|
GlobalInitIsCalledGuard() {
|
if (!GlobalInitAlreadyRun()) {
|
LOG(WARNING)
|
<< "Caffe2 GlobalInit should be run before any other API calls.";
|
}
|
}
|
};
|
|
/**
|
* @brief Initialize the global environment of caffe2.
|
*
|
* Caffe2 uses a registration pattern for initialization functions. Custom
|
* initialization functions should take the signature
|
* bool (*func)(int*, char***)
|
* where the pointers to argc and argv are passed in. Caffe2 then runs the
|
* initialization in three phases:
|
* (1) Functions registered with REGISTER_CAFFE2_EARLY_INIT_FUNCTION. Note that
|
* since it is possible the logger is not initialized yet, any logging in
|
* such early init functions may not be printed correctly.
|
* (2) Parses Caffe-specific commandline flags, and initializes caffe logging.
|
* (3) Functions registered with REGISTER_CAFFE2_INIT_FUNCTION.
|
* If there is something wrong at each stage, the function returns false. If
|
* the global initialization has already been run, the function returns false
|
* as well.
|
*
|
* GlobalInit is re-entrant safe; a re-entrant call will no-op and exit.
|
*
|
* GlobalInit is safe to call multiple times but not idempotent;
|
* successive calls will parse flags and re-set caffe2 logging levels from
|
* flags as needed, but NOT re-run early init and init functions.
|
*
|
* GlobalInit is also thread-safe and can be called concurrently.
|
*/
|
CAFFE2_API bool GlobalInit(int* pargc, char*** argv);
|
|
/**
|
* @brief Initialize the global environment without command line arguments
|
*
|
* This is a version of the GlobalInit where no argument is passed in.
|
* On mobile devices, use this global init, since we cannot pass the
|
* command line options to caffe2, no arguments are passed.
|
*/
|
CAFFE2_API bool GlobalInit();
|
} // namespace caffe2
|
#endif // CAFFE2_CORE_INIT_H_
|